少侠们好~
好久不见了,今天总算又和大家见面了。。。
正如你从标题里看见的,这次的内容是关于函数的,
虽然有点炒冷饭的嫌疑,
但是没办法,
毕竟函数是大多数少侠绕不过去的一道坎,
炒来炒去,
说不定熟了就绕过了。。。
好了,下面开始进入正题,
正文
首先,
这有一个简单的函数:
然后,现在少侠你有5秒时间从这个函数中拿到天辰dreamer。
5~
4~
3~
2~
1~
好了,时间到了,
下面是这次的答案:
嗯,这个答案简单得仿佛在侮辱少侠你的智商。。。
所以,
接下来我们要玩一个难度大些的,
从下面这个函数中拿到天辰dreamer:
这次少侠你有10秒时间来完成,
“。。。。。。真是无聊至极了”
好吧,这次的答案也很简单,
我们可以先调用一次two函数,
获取到里面的one函数,
然后再调用一次one函数,
获取到天辰dreamer:
或者我们也可以直接连续调用2次two函数,省略中间过程:
OK,
恭喜少侠你成功浪费掉了1分钟时间,
因为这2个例子确实有点废话的感觉,
但是!
在这个两个例子中,
确实也有一些有用的规则,
Rule1: 我们可以从一个函数中返回另外一个函数,当然,你也可以传递一个函数到另一个函数中。
Rule2: 返回的函数能获取到它定义时外层函数中的元素,即使是过后才调用。
换成装逼点专业点的词汇就是高阶函数(Higher-order function)和函数闭包(closure)。。。
没错,
就是那些被炒了无数遍,
随时随地都能看到相关文章,
到最后甚至看着就无聊的话题。。。
“那么既然这么无聊了,天辰你为什么还要说呢?”
“这么久没写文章,好不容易来一篇,就给我们看这个?”
“对啊对啊,对得起你100多个幽默风趣机智可爱的小粉丝吗?”
“。。。。。。。”
好吧,
主要是,
它们确实非常非常非常重要,
很多好玩的东西都需要在它基础之上才能完成。
还有就是暂时确实还没想好其他有趣的话题。。。
好了,
回到正式话题来,
在上面的基础上,我们有时候还会遇见一个问题,
那就是既然函数内部可以获取到外部函数的元素,
那么如果有多个同名的元素,到底应该获取哪一个呢?
比如下面这样:
又或者说,函数参数上也有叫做value的参数:
在这个函数中,有4个叫做value的元素,那么最终的value会获取哪一个呢?
正确答案是哪个最近就获取哪个。
去掉one函数内部的value值:
别问我为什么,
别问我为什么不是哪个最远就获取哪个。
可能是因为它总得有个规则。
也可能是因为懒。。
这就是我们今天的第三条规则了:
Rule3: 当一个函数开始寻找某个元素时,它会从最内部开始依次向外部寻找,如果找到了多个相同名称的元素,它会采用最近的那一个。
好了,
现在少侠你已经掌握了3条关于函数的有趣的规则,
那他们有什么用呢?
第一个用处是可以帮助你在函数内部封装一些数据,
然后返回一个只具有特定功能的函数来操作它。
在这个例子中,
getArrayBy函数会根据你传递的字符串是even还是odd来返回nums中的偶数和奇数,或者默认返回nums的一份拷贝,
除此之外,没有其他任何方式能接触到nums本身,能够保证它的安全性和私密性,也可以防止被意外串改。
“哦,这样啊,朕知道了~”
“等一等!少侠,还有一个细节地方~”
既然少侠你已经知道了内部函数可以访问定义时外部函数中的元素,
那么我们把isOdd和isEven函数放在arrayMachine里面也许会更好一些,
反正在getArrayBy内部也能访问到~
不信?
不信的话可以照下面这样测试一下:
当然,也有更实用一些的例子,比如下面这个用来生成数据结构栈的函数:
怎么样?少侠。
还是挺有用的吧?
除了上面的情况之外,
另外比较有用的情况可能会是函数装饰器(function decorator),
或者说函数盒子,
比如下面这个once函数:
这个函数有什么用呢?
假如你有一个函数,出于某些情况,比如支付等等,
你想让这个函数只被调用一次,避免重复操作。
你就可以使用once函数处理它,经过once函数处理后的函数,只有第一次调用时有效。
once函数在内部保存了一个变量done,
返回了一个新函数decoratedFn,
在上面的例子就是onlySayHiOnce函数,
onlySayHiOnce在调用时会先判断once中的done是否为true,
如果已经为true了,就什么也不做,
否则,它才会调用之前传递进来的函数fn, 并把参数传给它,
同时它也会把once中的done设置为true,
这样以后调用时获取到的done总是为true, 就不会有任何效果了。
正如少侠你看见的,
once函数给我们原来的函数增加了一些功能,
就好像给装饰了一遍,所以通常这种函数也叫做函数装饰器,
不过,
那为什么又叫做函数盒子呢?
因为我觉得函数盒子听起来好玩一些,哈哈哈。。。
今天第二个有用的函数盒子可能是unary,
unary盒子会让你的函数变成只会接受一个参数的函数,
即使这个函数本来可以有多个参数:
unary函数能够解决下面这样的问题:
你可能期望结果是[1, 2, 3],但实际上不是。
造成这样的原因是系统内置的parseInt实际上可以接受一个数字作为第2个参数,
这个参数可以告诉你希望转换的进制:
然后。。。碰巧的是,数组自带的map,它会给你传递3个参数。。
当前元素,当前元素的索引,以及数组本身,
不好意思,你需不需要我不管,反正我就是要传3个参数!
然后就变成了。。。
要解决这个问题的话,你可以显示地手动只传递一个参数,
另外就是使用unary函数:
(哎呀,一不小心还解决了一道面试题,优秀~)
这个问题也告诉了我们一个问题,
一定要认真了解你正在使用的函数,
不要凭感觉哦,少侠~
“天辰,道理我都懂了,不过好像使用unary函数更麻烦一些,有什么意义呢?”
“毫无疑问,当然不是为了装逼~”
完全OK~
恭喜你,
少侠,
你又成功发现并阅读完了一篇文章,
按照惯例,
谢谢少侠你看到了这里,
然后~
希望少侠你能从中发现一些有趣的东西,
(或者人也行,比如机智的我)
当然,,
类似的函数盒子实际上还有很多,
不过不能一次性给放这里了,
因为可能是以后的素材。。。
“叮~ 从杂货店买到一本烂大街的closure技能书,已添加到储物袋里。”
“叮~ 发现两个奇怪的函数盒子,已添加到储物袋里。”
“叮~ 额外发现一个隐藏的封印的道具,栈(stack),栈。栈。。暂时不知道有什么用。。。”
(好奇怪的谐音梗。。。)
额外资源
自由变量(free variable)
不属于函数内部的变量叫做自由变量
纯函数(pure function)
不包含自由变量的函数叫做纯函数。
比如下面的one函数就是一个纯函数。
闭包函数(closure)
包含自由变量的函数叫做闭包函数。
下面two函数内部的one函数就是一个闭包函数
甩锅时间
少侠你可能会觉得比较奇怪的是,
为什么不直接解释闭包,作用域等等,而只是说了几个规则,
实际上,
不管是闭包,或是作用域等的,都只是某种语言规则,
有时候太纠结名称可能反而不好,
重要的是明白它们到底是在做什么。
比如少侠你可以说上面的规则是关于闭包和作用域,
或者你也可以换个角度,
说上面的只是关于如何在函数内部获取到一个值,
when, where, how,以及why。
why呢?
这里确实没有why,
因为why需要留给少侠你自己去思考~
你可能关心的问题
1、明说了,没看懂,怎么办?
少侠,不要在一棵树上吊死。。。
多看看不同的文章,综合归纳,做到举一反三,
不过,记得只给我点赞就行了。。哈哈。
2、再问一遍,为什么代码要用图片呢?
第一,好看,
第二,我自己做的,
第三,我自己做的,然后我又觉得很好看。
第四,你们手机上滑来滑去看代码不觉得麻烦?还不如图片放大看方便。
好了,溜了溜了~
少侠,江湖路上,有缘再见~
热门评论
?100多小粉丝不在这,从掘金复制过来的。。。