今天看见一道自认为比较有难度比较绕的闭包题目,倒腾了好一会才弄出答案来,这题目是别人博客里面写的,本着“自己懂还不算真的懂,给别人讲懂了才算真的懂的原则”,故我在这篇博客里面来说说这道题目
这是本人第一次描述这些题目,如果有用词不当,请提出^_^
原作者的链接我会赋到最下面,如有冒犯请通知我,我会删掉的。
题目如下
1 | function fun(n,o) { |
是不是有点懵逼?如果是,请先冷静一下哈,太懵逼是没办法解决问题的(虽然我看到第一眼就懵了,但是你可以慢慢来,还是可以梳理好的)。如果不是那你一定在闭包上面有深深的理解。
第一个 fun
函数,是标准具名函数声明,返回了一个对象字面量表达式,也就是一个 object
。
第二个 fun
是一个属性,是匿名函数表达式。
第三个 fun
是调用的,也就是第一个fun
,有点递归的意思。这里或许你会问为什么不等于第二个 fun
?其实我们可以将以下代码在浏览器console
测试一下
假如是第三个fun是同第二个一样:1
2
3
4
5
6var o={
fn:function (){
console.log(fn);
}
};
o.fn();//ERROR报错
我们发现它最终会报错,显示fn is not defined(...)
下面再看另一个1
2
3
4var fn = function (){
console.log(fn);
};
fn();//function (){console.log(fn);};正确
这次就没有报错了,var
在函数外部创建了一个fn,函数内部找不到fn则可以向上寻找,但是第一种是在函数内部创建的,没办法找到。
所以我们可以得知,第三个函数是第一个的这个fun
所以我们回顾一下原来的函数
1.第一行
1 | var a = fun(0); a.fun(1); a.fun(2); a.fun(3); |
首先fun(0)
,即n = 0
传入了fun(n,o)
,此时o
没有值,则为undefined
:
故第一个输出为 undefined
接着的return返回了一个对象字面量表达式,也就是类似下面1
2
3
4
5var a = {
fun:function(m){
return fun(m,n);
}
}
接着的 a.fun(1)
参数 m = 1
, n
的值我们之前在fun(0)
里面知道了——是 0
。则下面的fun(m,n)
则是 fun(1,0)
,再倒回去看函数第一个fun(最外面的那个)m->n
, n->o
,所以打印出来的o
也就是最后n
的值,为 0
那么 a.fun(2)
呢?其实也是差不多的,m = 2
的时候,n还是原来的 n = 0
,你问为什么?因为在var a = fun(0)
的时候已经确定了呢,所以最终输出 0(第三个fun
的参数n
将值赋给了第一个fun
的o
)
所以这么看来的话,第一行的第三个是不是也是很好解决呢?
和前面两个一样也是等于0
所以第一行的答案是:
undefined 0 0 0
2.第二行
1 | var b = fun(0).fun(1).fun(2).fun(3); |
- 首先第一个值是
undefined
是同刚刚第一行的一样的。 - 那么接下来看又引用了
fun
这个方法,也就是m = 1
,n是原来的0,也就是最后o = 0
,那么第二个输出的数字就为 0 - 此时还没完呢,接着又马上来了个
fun(2)
,此时的fun其实又变成了最外层的那个fun
,那么m = 2,n = 1
,对应fun(n,o)
就是n=2,o=1
.此刻你应该明白了,下一个输出的数是 1 - 最后一个是
fun(3)
,这个又再次变成了fun里面的那个方法fun
里面的函数,由于上次n=2 m=3
=>fun(3,2)
,最后一个输出 2
所以第二行的答案是:
undefined 0 1 2
3.第三行
1 | var c = fun(0).fun(1); c.fun(2); c.fun(3); |
- 由于前面两个在第二行里面是类似的,这边就直接跳过了,输出undefined 和0
- 这时候,
c.fun(2)
=>fun(m,n)
=>m = 2
,n
在上一个已经等于1
, 也就是在fun(n,o)
里面n =2,o = 1
;
所以此次输出 1 - 第三个
c.fun(3)
=>fun(m,n)
=>m=3,n=1
。所以最后在函数fun(n,o)
里n=3,o = 1
,所以还是输出1
所以第三行的答案是:
undefined 0 1 1