在廖老师的JavaScript教程中,发现了一个有趣的例子
脑洞大开
很久很久以前,有个叫阿隆佐·邱奇的帅哥,发现只需要用函数,就可以用计算机实现运算,而不需要0
、1
、2
、3
这些数字和+
、-
、*
、/
这些符号。
JavaScript支持函数,所以可以用JavaScript用函数来写这些计算。来试试:
'use strict';
// 定义数字0:
var zero = function (f) {
return function (x) {
return x;
}
};
// 定义数字1:
var one = function (f) {
return function (x) {
return f(x);
}
};
// 定义加法:
function add(n, m) {
return function (f) {
return function (x) {
return m(f)(n(f)(x));
}
}
}
// 计算数字2 = 1 + 1:
var two = add(one, one);
// 计算数字3 = 1 + 2:
var three = add(one, two);
// 计算数字5 = 2 + 3:
var five = add(two, three);
// 你说它是3就是3,你说它是5就是5,你怎么证明?
// 呵呵,看这里:
// 给3传一个函数,会打印3次:
(three(function () {
console.log('print 3 times');
}))();
// 给5传一个函数,会打印5次:
(five(function () {
console.log('print 5 times');
}))();
// 继续接着玩一会...
结果
print 3 times
print 3 times
print 3 times
print 5 times
print 5 times
print 5 times
print 5 times
print 5 times
很神奇,对吧?刚开始也是似懂非懂,但我认为,本质上是调用函数的次数
当然,要理解这个例子,首先要理解好闭包
闭包
比如廖老师里面的这个例子
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15
我们可以发现,第一次lazy_sum()
,返回的其实是
function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
来试试lazy_sum([1, 2, 3, 4, 5])()
,得到的结果是15
改一改上面的例子
function lazy_sum(arr) {
var sum = function () {
return function(){
return arr.reduce(function (x, y) {
return x + y;
});
}
}
return sum;
}
再来试试这个
lazy_sum([1, 2, 3, 4, 5])()(); // 15
或许你已经有一点头绪了,其实括号的数量可以简单的和 return
的数量结合起来看,有几个括号,就说明执行到第几层。
对于下面的例子来说,关于闭包了解这么多应该够了,更多的可以网上找更详细的解释
一个例子
来一步一步剖析吧,看这个函数
// 给3传一个函数,会打印3次:
(three(function () {
console.log('print 3 times');
}))();
把它弄到同一行
(three(function () { console.log('print 3 times');}))();
中间的function
用func
替代,也就是
(three(func()))()
把 three
转换成另一个形式
add(one,two)(func())()
根据上面的发现,有三个括号,直接执行add
函数三层,即
one(func())(two(func())())
看上去还有点复杂,但是我们先解析one
第二个括号里的内容
one(func())(add(one,one)(func())())
one(func())(one(func())(one(func())()))
好像更复杂了,但给它稍微分一下,应该就能变简单了
20200117220844122.png
大概知道了吧,其实就是one(func())(...)
形式的嵌套函数,根据one
函数的定义,可以变成
one(func())(one(func())(func()))
//one(func())()变成func(),只不过传进x的值是undefined,传进f的值是func
func
函数其实就是输出一个语句,然后返回undefined
罢了,所以最里面的func
函数执行完就变成
one(func())(one(func())())
//然后
one(func())(func())
//再然后
one(func())()
//再再然后
func()
我们可以注意到,上面的例子输出了3次语句,其实就是执行了三次func()
对于函数five
也是一样,就是多执行了两次