不二如是 发表于 2017-7-28 10:17:16

0 1 5 8 ★ 小王子与Js教主 |【By-老刘】

本帖最后由 不二如是 于 2017-7-28 10:25 编辑

推荐阅读:

0 1 5 7 ★ 寥寥数行代码玩透“hoist”|【高级玩家必看】

0 1 3 2 ★ 小心! 这里有'隐式的强制转换'!!! | 【握草,Boom~~~】

0 1 3 3 ★ 得“闭包”者得天下! | 【精英版】





登场人物名:

小兰 : lambda

邱大教主:阿隆佐.丘齐(Alonzo Church)Lambda演算发明人






[*] 拜函数教


Java 小王子在 JavaScript 王国待了也有一段时间了。

这里虽然不像 Java 帝国那样规范严苛,但也因此千奇百怪,五光十色。

要说小王子最喜欢待的地方,那还是人来人往的 JSON 酒馆,不仅有上好的酒菜,还有机会认识到各式各样的人。

这不,一来二去他已经和上回认识的眼镜官员成了朋友,甚至私底下还称兄道弟的。

这一天小王子又和眼镜大哥一起约来吃酒。

才寒暄了几句,筷子还没动,酒馆门口就发生了一点骚动。

只见来了一位看起来像是教书先生的精瘦男子,旁边还有些随从。

“...... 大哥,这人什么来头,气度不凡啊。”

小王子悄声向旁边的眼镜官员问到。

“哈哈,他是拜函数教的邱大教主,最近他们教派的信众激增啊,真是风水轮流转。”

“函数式?“

以前随父亲经商途中是听说过他们的事情,好像非常古老而且高深莫测啊。

据说只有学者和虔诚的教徒才会加入他们,怎么最近也接收新人了?

“小弟果然是见多识广,不错,在很久以前的确是这样,不过为何有大批新教徒这种事情也不在我的管辖范围内啊,所以也不太清楚。但是毕竟我是本国语言规范审查官,还是与他打过一些交道。不妨我们邀请他来一起喝酒,你亲自问他。”

小王子本来听到眼镜大哥也不了解情况正有些失望。

突然得知可以直接面对面打探对方的底细,顿时兴奋了起来。

“那太好了!”

“这不是眼镜老弟么,别来无恙啊。”

“主教兄,甚好甚好,要不这顿我请?小二!”

饭菜上桌,互相客套了几句之后,话题就开始了。

“主教兄,这是我最近认识的朋友,年纪轻轻就周游四方,他有些事情要问你。”

“哦?”函数式主教把目光放了过来,“有何见教?”

“久闻贵教派向来神秘,为何最近有如此多的新教徒加入呢?”

“哈,这个嘛 ... 现在的年轻人都不喜欢条条框框,本教向来以简洁强大著称,自然就受欢迎了。”

小王子心想,这个教主倒也是有话直说、自卖自夸。

不过难道没了面向对象这种强大的武器,他还能变出怎么样的花儿来?

“那还敢请教教主大人,依你看要怎么实现 Animal, Cat, Dog 这些对象呢?”

想了一会儿,小王子认为不如直接发问。

“这个嘛,本教派并无对象这种说法,不过如果你愿意,也可以构造一个对象出来,只需要......”

“我们拜函数教不用对象~”

还没等着主教说完,旁边的妹子突然发话了。

“哦,小兰,你来说吧。”

这位被叫做小兰的少女像是主教的助手,看起来深得主教信任。

“嘻嘻,教主大人说的太复杂了,其实实现你说的那些根本不用什么对象。”

“哦?那该怎么做?”

小王子顿时来了兴趣。

[*]一等公民:函数


“你想啊,搞出来这些猫啊狗啊的,不就是想让他们都可以吃东西么?干嘛要封装到一个对象中,太压抑了”



哦!

Java 小王子恍然大悟,在自己的Java帝国,法律非常严格, 类和对象才是一等公民。

函数是不可能独立存在的, 你即使是想输出一个简单的hello world , 也必须写一个类。

在类中写一个方法 , 在这个方法中才能输出hello world 。

在这里函数已经翻身做主人,成为了一等公民。

再也不用困在对象的牢笼中,声明后就可以直接使用。

“也就是说,猫、狗都可以直接拿来调用咯?”



“是的呢~ 不止是猫、狗,连人都能作为参数调用呢, 只要一个对象有name这个属性就行啊”

小兰的脸上还是一样的笑容。



长期在一个强类型的语言中生活,小王子对这种有点“变态”的灵活性还真不习惯。

他说:

“在Java帝国,方法的参数都有确定的类型,如果你的方法写错了,IDE就能自动帮你检测, 减少了很多错误,现在可就没这种福利了。”

“有得必有失嘛”

小兰笑道

“你可以多写一点单元测试来保证正确性啊”

“既然函数是一等公民, 我相信它不止这点能耐吧?“

“那是自然, 我们这里的函数还可以作为参数传递给另外一个函数呢!”



小王子突然想到父王给自己讲过,要在Java8中引入函数式编程。

可以把一个所谓的lambada 表达式传递给另外一个函数, 省去了创建类或匿名类的开销。

但是宫廷老师偷偷地告诉过自己:

“那只是半吊子的函数式编程,每个lambda表达式其实还得和一个函数接口相匹配, JDK在背后做了类型的推断”

“函数既然能作为参数,我猜肯定也能作为返回值吧?”

小王子觉得拜函数教的邱大教主在场, 这个天真活泼的小兰好像不敢给自己透露太多, 只好主动发问。

“你这个外乡人很聪明嘛, 估计有不少编程基础吧?”

小兰又展示了一段代码:



果然和自己的猜想一致!

作为皇族,小王子确实非常聪明,他很快就想到了另外一个问题:

“如果内部的eat函数访问了外部函数的变量会发生什么状况?”




按照我们Java 帝国的理论, 函数在被调用的时候是以栈帧的方式被压入栈中的。

函数的局部变量也在栈帧当中, 当这个函数返回,对应的栈帧就会被清除,局部变量自然也不可用了。

现在这个eat函数还能再使用createEatFunction()函数的desc这个变量吗?

或者在调用它的时候会使用外边的全局desc 变量?

从而输出 "dog 正在吃东西”?

函数作为返回值看起来很美, 但细节着实让人费解啊?

[*] 闭包


看到小王子像上次一样又“卡”住发呆了, 眼镜官员笑着对主教和小兰说:

这小子肯定又在深思了。

小兰说:

“这个外乡人确实不一般,思考很深入,让他的CPU再运转一会儿吧”

小王子没有找到答案,从思考中回来,看到大家都盯着自己看。

有点不好意思, 把疑惑给大家说了。

“外乡人,Java 把你毒害得不浅, 我看你资质不错,不如忘掉Java 那丑陋的模型, 加入到我们拜函数教来吧。 将来你继承我的位置也未可知啊!”

邱大教主看了小兰一眼,意味深长地说。

小兰接口说:

“还是先解释下你的疑惑吧, 你那段代码的输出应该是‘dog is eating’ , 而不是 ‘dog 正在吃东西’”

小王子说:

“这我猜到了, 我就是不理解一个函数(createEatFunction)都执行完了, 为什么它的变量(desc)还能被 后面执行的函数(eat)来使用。”

“要不说你的java毒中的很深啊, 你换个角度想想,局部变量在函数执行完以后还可以被访问。那它肯定不能存在于你说的那个什么java栈帧中。” 小兰说。

“那它放在那里?”

“在JavaScript 当中,有个作用域链(scope chain)的东西,它定义了一个函数激活执行的时候去哪儿找变量的值,比如eat函数的作用域链是这样的:”

此图只是示意图,并不严谨,例如没有表达出Activation object, Variable Object等概念

小王子看着这个图,马上就明白了,这个eat函数没有定义desc 这个变量。

所以就沿着链去查找, 在createEatFunction作用域去查找。

如果还找不到,就到global 作用域中查找......

这个例子中,在createEatFunction的作用域中有定义,于是就直接使用了。

“可是,createEatFunction 已经执行完了, 难道它的desc 变量不删除吗? ”

小王子不服气地说 。

“那肯定不能删除喽”

小兰说

“这里和你熟悉的java 有个重要的不同, 当你执行creatEatFunction的时候, eat函数才会被创建出来,此时eat函数就会把外部函数的作用域链记录下来(其中包含desc=' is eating'),以便执行时使用”

“哦,这个作用域是在函数创建时刻发生关联的,而不是运行时刻”

“没错, 这叫做静态作用域(static scope),或者叫词法作用域(lexical scope)。当eat函数被激活执行,就可以在createEatFuncction中找到desc的值,而不是在全局中找到desc的值。 ”

小兰接着说。

“我再给你看个例子, 你就理解这个静态作用域了”



小王子说:

“这段代码的输出应该是2 啊, 还有什么可说的,哦,不对不对,应该输出1, 静态作用域!   函数foo在创建的那一刻, 已经确定了它会和包含x=1的全局作用域关联 , 所以在运行的时候也只会从全局作用域查找,而不是从bar 函数的作用域中找x ”

“看来你已经Get到了, 这个静态作用域是实现闭包的一个必需条件, 你听说过闭包吧?”

小王子说:

“我听父王说过,但是不知道怎么回事....”

小王子说漏了嘴,赶紧打住。

小兰像没有听到一样,继续讲闭包:

“闭包在JavaScript当中就是一个函数和以静态方式存储的父作用域的一个集合体,通过这个集合体,一个函数就可以访问外部函数的变量了。 ”

“所以eat函数就可以访问外部函数的变量了!闭包这个名称有点古怪,不过背后的概念还是比较清晰的”

小王子赶紧说。

[*]尾声


“咳咳,小莱你够了。客人都被你吓到了。”

这时,在旁边默默看着的邱大教主说话了。

经过这一番交谈,小王子震惊于函数式的独特之处,尤其是和Java帝国的不同。

不过毕竟是皇族,阅历丰富,他还是悟出了一点门道。

“我大概明白了一点,由于 JavaScript 是动态类型,其实无论是函数还是对象,在这里都可以做为一个值来传递。函数式里面偏向对值直接进行处理,通过对这些值的传递和组合,就可以组装实现更高级的功能。”

“不错不错,我看你这位朋友的来头可不一般啊,新加入的信徒大多都经过漫长的适应期才能理解,他却立即悟出这些道理来。”

邱大教主对小王子赞赏有加,或许以他的智慧已经识破了小王子的身份。

“不不不,还是因为小兰妹妹讲的好啊。”

小王子脸红的说道。

“这还不是多亏了我们的原型才能自由灵活的实现各种编程范式么。”

眼镜大哥也参合了起来。

“哈哈哈,你又在自夸了。”

“来,说了这么多 eat,不说了,吃菜吃菜~”

**** Hidden Message *****

TCY 发表于 2019-6-2 17:25:23

我操,Java还有这限制!一定要创建object?

天地~玄黄 发表于 2019-7-11 17:00:07

看看

TCY 发表于 2020-2-28 11:20:58

问下这个老刘是谁?

weiter 发表于 2020-3-2 14:18:16

666

一笙彤 发表于 2020-6-13 16:35:35

0

omg123460 发表于 2021-10-15 16:34:21

·1

jack6666 发表于 2022-10-6 20:40:24

1

dd8556471 发表于 2022-10-20 13:40:54

謝謝提供資料

peanutfs13 发表于 2023-9-13 14:24:31

啊啊啊感觉没太看懂。。。

孙忠亮 发表于 2023-10-31 16:45:19

1
页: [1]
查看完整版本: 0 1 5 8 ★ 小王子与Js教主 |【By-老刘】