闭包题目的思考分析
程序员文章站
2022-07-07 20:30:25
以上三题分别打印出什么? 此题出自 "这里" 这已经不是我第一次看这套题了。第一次看到这题的时候,我没有完全做出来,感觉里面的fun函数(方法)太绕了,做到后面都晕了,不知道到底指的是哪个fun。于是花了半天时间把这几套题搞懂了(当时觉得自己搞懂了,捂脸),隔了两天我把题目拿给其他人做,顺便打算自己 ......
function fun(n,o){ console.log(o); return { fun:function(m){ return fun(m,n) } } } var a = fun(0); a.fun(1); a.fun(2); a.fun(3) // undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3) // undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3) // undefined,?,?,?
以上三题分别打印出什么?
此题出自
这已经不是我第一次看这套题了。第一次看到这题的时候,我没有完全做出来,感觉里面的fun函数(方法)太绕了,做到后面都晕了,不知道到底指的是哪个fun。于是花了半天时间把这几套题搞懂了(当时觉得自己搞懂了,捂脸),隔了两天我把题目拿给其他人做,顺便打算自己讲一遍给对方听,发现自己又傻又晕了,最后还给人笑了(哭)。然后又看了第二遍,又感觉懂了。今天浏览网页的时候,又翻到这个,想着看能不能做出来。我是拿着纸笔写的,又发现自己要晕了。终于决定:不行,我得自己写一遍这个思考过程,不然下次我还得晕~~~。所以就有了下面这篇思考分析。
分析如下:
tips:我把外层的fun叫做函数fun,return 里面的fun我叫方法fun。这里很关键,分清楚这两个就比较不容易错了
第一道:var a = fun(0); a.fun(1); a.fun(2); a.fun(3) // undefined,?,?,?
第一步:执行fun(0),将参数代入函数fun,看看执行情况 var a = fun(0) = (function(n=0){ console.log(o); // undefined;因为没有第二个参数o。 return { // return后面是带着fun方法的对象,对象里面的内容不作执行,但会带上n这个*变量的值0; fun:function(m){ return fun(m,0) // 这里的n是0 } } })(0) 所以a = fun(0)打印的值:undefined 返回的值为: var a = fun(0) = { fun:function(m){ return fun(m,0) } } 第二步:执行a.fun(1),即执行对象a的方法fun(m),而方法fun(m)又return回函数fun(m,0),最终执行的是这个函数fun(m,0),这里的m就是1 a.fun(1) = (function fun(m=1){ return fun(1,0) // 该方法将返回函数fun(1,0),而函数fun(1,0)又将按第一步一样执行一次。 })(1) 即: a.fun(1) = fun(n=1,o=0) = (function(n=1,o=0){ console.log(0) // 0; 这里的0就是第二个参数o return { // return带fun方法的对象 fun: function(m){ return fun(m,1) // 这里的n是1 } } })(1,0) 所以a.fun(1)打印的值为:0 返回的值为: a.fun(1) = { fun:function(m){ return fun(m,1) } } 第三步:执行a.fun(2),即执行对象a的fun方法,同第二步,只是参数有变,最终执行的是函数fun(2,0) a.fun(2) = (function fun(m=2){ return fun(2,0) })(2) 即: a.fun(2) = fun(n=2,o=0) = (fun(n=2,o=0){ console.log(0); // 0,这里的0即是o这个参数 return fun: function(m){ return fun(m,2) // 这里的n是2 } })(2) 所以a.fun(2)打印的值为:0 返回的值为: a.fun(2) = { fun: function(m){ return fun(m,2) } } 第四步:a.fun(3),同第二、第三步(过程略),最终执行的是函数fun(3,0) 所以a.fun(3)打印的值为: 0 返回的值为: a.fun(3) = { fun: function(m){ return fun(m,3) } }
第二道:var b = fun(0).fun(1).fun(2).fun(3) // undefined,?,?,?
第一步:先执行fun(0) 由上面第一道分析可知: fun(0) 打印的值为:undefined 返回的值为: fun(0) = { fun:function(m){ return fun(m,0) } } 第二步:执行fun(0).fun(1),其实这里也和上面第一道的第二、三、四步是一样的 fun(0).fun(1)即执行fun(0)的方法fun(),而方法fun()又将return回函数fun(m,0),所以,fun(0).fun(1)最终执行的是函数fun(m,0),m就是参数1。 fun(0).fun(1) = fun(n=1,o=0) = (function(n=1,o=0){ console.log(0) // 0,第二个参数o return { fun: function(m){ return fun(m,1) // 这里的n是1 } } })(1,0) 所以fun(0).fun(1)打印的值为:0 返回的值为: fun(0).fun(1) = { fun: function(m){ return fun(m,1) } } 第三步:执行fun(0).fun(1).fun(2),即执行fun(0).fun(1)的方法fun(2),fun(2)又返回函数fun(2,1),所以fun(0).fun(1).fun(2)最终执行的是函数fun(2,1) fun(0).fun(1).fun(2) = fun(n=2,o=1) = (function(n=2,o=1){ console.log(1); // 1,第二个参数o return { fun: function(m){ return fun(m,2) // 这里的n是2 } } })(2,1) 所以fun(0).fun(1).fun(2)打印的值为:1 返回的值为: fun(0).fun(1).fun(2) = { fun: function(m){ return fun(m,2) } } 第四步:执行fun(0).fun(1).fun(2).fun(3), 按上面分析,这里最终执行的是函数fun(3,2) fun(0).fun(1).fun(2).fun(3) = fun(n=3,o=2) = (function(n=3,o=2){ console.log(2); // 2,第二个参数o return { fun: function(m){ return fun(m,3) // 这里的n是3 } } })(3,2) 所以fun(0).fun(1).fun(2).fun(3)打印的值为:2 返回的值为: fun(0).fun(1).fun(2).fun(3) = { fun: function(m){ return fun(m,3) } }
第三道:var c = fun(0).fun(1); c.fun(2); c.fun(3) // undefined,?,?,?
由上面分析可知:(第二道第二步返回的值) var c = fun(0).fun(1) = { fun: function(m){ return fun(m,1) } } 打印的值为: 0 接下来分析后面的题 第一步:执行c.fun(2), return回函数fun(2,1),最终执行的也是函数fun(2,1)。其实这也和第二道的第三步是一样的。 c.fun(2) = fun(n=2,o=1) = (function(n=2,o=1){ console.log(1) // 1,第二个参数是1 return { fun: function(m){ return fun(m,2) // 这里的n是2 } } })(2,1) 所以c.fun(2)打印的值为:1 返回的值为: c.fun(2) = { fun : function(m){ return fun(m,2) } } 第二步:执行c.fun(3),return回函数fun(3,1),也是最终执行的函数。同第一步。 所以c.fun(3)打印的值为:1 返回的值为: c.fun(3) = { fun: function(m){ return fun(m,3) } }
为了方便对比这三道题的结果,用表格记录如下:
表头 | 第一题 | 第二题 | 第三题 |
---|---|---|---|
fun(0) | undefined | undefined | undefined |
a.fun(1) fun(0).fun(1) fun(0).fun(1) |
0 | 0 | 0 |
a.fun(2) fun(0).fun(1).fun(2) fun(0).fun(1).fun(2) |
0 | 1 | 1 |
a.fun(3) fun(0).fun(1).fun(2).fun(3) fun(0).fun(1).fun(3) |
0 | 2 | 1 |
通过分析过程可知,有两点是需要注意的:
- 最终执行的始终是fun函数,就是最外层的function,因为执行它才有打印的值。
- 参数的变化。方法fun和函数fun的参数是不一样的,而且它们之间的参数有交叉,所以很容易弄混。