欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

闭包题目的思考分析

程序员文章站 2022-03-31 18:19:52
以上三题分别打印出什么? 此题出自 "这里" 这已经不是我第一次看这套题了。第一次看到这题的时候,我没有完全做出来,感觉里面的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

通过分析过程可知,有两点是需要注意的:

  1. 最终执行的始终是fun函数,就是最外层的function,因为执行它才有打印的值。
  2. 参数的变化。方法fun和函数fun的参数是不一样的,而且它们之间的参数有交叉,所以很容易弄混。