关于JS闭包中用函数模仿计算的理解

问题链接: 链接直达

关于末尾的那个脑洞大开的函数,谷歌一圈无果,最后尝试自己用最简单粗暴的土方法来理解:

首先把来看看one函数

1
2
3
4
5
6
// 定义数字1:
var one = function (f) {
return function (x) {
return f(x);
}
};

上面是老师的版本,精简后变成

1
2
3
4
5
var one = function (f) {
return function () {
return f();
}
};

精简后就容易看出来:one函数干的事情,其实就是传入一个f()函数,最后返回一个待执行的f()函数

再来看看调用one函数来实现打印一次的代码:

1
2
3
(one(function () {
console.log('print 1 times');
}))();

其中传入的参数是一个函数(我们暂且把它叫做print函数):

1
2
3
function(){
console.log('print 1 times');
}

经过one函数处理后,最终返回一个待执行的print函数,最后再加一对括号(),使打印函数开始执行,于是在console就可以看到打印出来”print 1 times”一次。

理解后,再来看add函数:
1
2
3
4
5
6
7
8
// 定义加法:
function add(n, m) {
return function (f) {
return function (x) {
return m(f)(n(f)(x)); //关键看这一行
}
}
}

上面是老师的版本,精简后:

1
2
3
4
5
6
7
function add(n, m) {
return function (f) {
return function () {
return m()(n()());
}
}
}

我们要关注的是m()(n()()),这里你可以理解为m()()嵌套n()()。执行顺序先执行n()()再执行m()()

再来看two函数:
1
var two = add(one, one);

传入了两个one函数。还记得one函数最终返回一个待执行的f()函数吗?于是tow函数相当于传入两个待执行的f(),最终变成一个会执行两次f()的待执行函数,因为函数又包多了一层,所以two函数最里层需要加多一对括号()

所以:

1
2
3
(tow(function () {
console.log('print 2 times');
}))();

最终会执行两次!

好了,看到这里,我想说,老师一下写个3和5的函数,相当于嵌套了3次和5次的函数。闭包本身就复杂,再嵌套个3次5次就非常难理解了!这是一个坑。所以这里你理解到第二层就够了,接下去的嵌套让计算机来算就好了。