闭包 -- 详解

原题如下:   

function func(n,o) {
    console.log(o)
    return {
        func:function(m){
            return func(m,n);
        }
    };
}

var a = func(0);a.func(1);a.func(2);
var b = func(0).func(1).func(2).func(3);
var c = func(0).func(1);c.func(2);  
  • 这段代码中出现了三个func函数,所以第一步先搞清楚,这三个fun函数的关系,哪个函数与哪个函数是相同的。

function func(n,o) {
  console.log(o)
  return {
    func:function(m){
      //...
    }
  };
}

  先看第一个func函数,属于标准具名函数声明,是新创建的函数,他的返回值是一个对象字面量表达式,属于一个新的object。

  这个新的对象内部包含一个也叫func的属性,通过上述介绍可得知,属于匿名函数表达式,即func这个属性中存放的是一个新创

  建匿名函数表达式。

  注意:所有声明的匿名函数都是一个新函数。

  所以第一个func函数与第二个func函数不相同,均为新创建的函数。

  •   函数表达式内部能不能访问存放当前函数的变量。

  1.   对象内部的函数表达式:
var o={
    fn:function (){
        console.log(fn);
    }
};

o.fn();//ERROR报错

     2.    非对象内部的函数表达式:

var fn=function (){
    console.log(fn);
};

fn();//function (){console.log(fn);};正确

    

  结论是:使用var或是非对象内部的函数表达式内,可以访问到存放当前函数的变量;在对象内部的不能访问到。

  原因也非常简单,因为函数作用域链的问题,采用var的是在外部创建了一个fn变量,函数内部当然可以在内部寻找不到fn后向

  上册作用域查找fn,而在创建对象内部时,因为没有在函数作用域内创建fn,所以无法访问。

  所以综上所述,可以得知,最内层的return出去的func函数不是第二层func函数,是最外层的func函数

  所以,三个fun函数的关系也理清楚了,第一个等于第三个,他们都不等于第二个。

  • 到底在调用哪个函数?

  再看下原题,现在知道了程序中有两个func函数(第一个和第三个相同),遂接下来的问题是搞清楚,运行时他执行的是哪个func

  函数?

      1.   第一行a

var a = func(0);
a.func(1);
a.func(2);
a.func(3);




/* a.func(1)     //一开始func(n=0,o=undefined)!!!!!!理解初始化状态这点非常重要 
 
a.func(m=1)→执行后→func(n=1,o=0)→n赋值为1,o赋值为0.
var a={
    func:执行console.log(0),返回:{
        func:function(1){
            return func(m,1)    //由于没有执行所以n不会赋值为undefined,o也不会赋值为1
        }
    }
}   */


/* a.func(2)    //一开始func(n=0,o=undefined)!!!!!!理解初始化状态这点非常重要 
 
a.func(m=2)→执行后→func(n=2,o=0)→n赋值为2,o赋值为0.
var a={
    func:执行console.log(0),返回:{
        func:function(2){
            return func(m,2)由于没有执行所以n不会赋值为undefined,o也不会赋值为2
        }
    }
}     */

同理 a.func(3)

  可以得知,第一个func(0)是在调用第一层fun函数。第二个func(1)是在调用前一个fun的返回值的func函数,所以:

  第后面几个func(1),func(2),func(3),函数都是在调用第二层fun函数

  即:

  在第一次调用func(0)时,o为undefined;

  第二次调用func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func

  函数func(1,0);所以o为0;

  第三次调用func(2)时m为2,但依然是调用a.func,所以还是闭包了第一次调用时的n,所以内部调用第一层的func(2,0);即o为0

  第四次同理;

  即:最终答案为undefined,0,0,0

       2.   第二行b

var b = func(0).func(1).func(2).func(3);//undefined,0,1,2
 
/*一开始func(n=undefined,o=undefined)*/
/*
    var b = func(n=0,o=undefined); 执行后,相对应改变局部变量n和o.
    执行console.log(undefined),返回:
    var b={
        func:执行func(n=1,o=0);console.log(0),返回:{
            func:执行func(n=2,o=1);console.log(1),返回:{
                func:执行func(n=3,o=2);console.log(2),返回:{
                    func:function(3){
                        return func(m,3)由于没有执行所以n不会赋值为undefined,o也不会赋值为3
                    }
                }
            }
        }
    }
*/

  先从func(0)开始看,肯定是调用的第一层func函数;而他的返回值是一个对象,所以第二个fun(1)调用的是第二层func函数,后

  面几个也是调用的第二层func函数。

  即:

  在第一次调用第一层func(0)时,o为undefined;

  第二次调用 .func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func

  函数func(1,0);所以o为0;

  第三次调用 .func(2)时m为2,此时当前的func函数不是第一次执行的返回对象,而是第二次执行的返回对象。而在第二次执行

  第一层func函数时时(1,0)所以n=1,o=0,返回时闭包了第二次的n,遂在第三次调用第三层fun函数时m=2,n=1,即调用第一层func

  函数func(2,1),所以o为1;

  第四次调用 .func(3)时m为3,闭包了第三次调用的n,同理,最终调用第一层func函数为func(3,2);所以o为2;

  即最终答案:undefined,0,1,2

        3.   第三行c

var c = func(0).func(1);  c.func(2);  c.func(3);

  根据前面两个例子,可以得知:

  func(0)为执行第一层func函数,.func(1)执行的是func(0)返回的第二层fun函数,这里语句结束,遂c存放的是func(1)的返回值,

  而不是func(0)的返回值,所以c中闭包的也是func(1)第二次执行的n的值。c.func(2)执行的是func(1)返回的第二层func函数,

  c.func(3)执行的是func(1)返回的第二层func函数。

  即:

  在第一次调用第一层func(0)时,o为undefined;

  第二次调用 .func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func

  函数func(1,0);所以o为0;

  第三次调用 .func(2)时m为2,此时func闭包的是第二次调用的n=1,即m=2,n=1,并在内部调用第一层func函数func(2,1);

  所以o为1;

  第四次.func(3)时同理,但依然是调用的第二次的返回值,遂最终调用第一层func函数func(3,1),所以o还为1

  即最终答案:undefined,0,1,1

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端e站

如果有所帮助,欢迎来杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值