zoukankan      html  css  js  c++  java
  • 一个题目引发的闭包、函数声明以及作用域的简单思考

    在segmentfault的微博看到了这样的一个标题,传送门:javascript关于闭包的面试题,顺手点开发现了一段这样的代码

     1 function f1(){
     2   var n=999;
     3   nAdd=function(){n+=1}
     4   function f2(){
     5     alert(n);
     6   }
     7   return f2;
     8 }
     9   var result=f1();
    10   result(); // 999
    11   nAdd();
    12   result(); // 1000

    这里倒是没什么问题,result为function f2(){alert(n);},nAdd为function(){n+=1;}。

    在f1的声明时决定了,result和nAdd二者对f1作用域内的n是共享的,因此也得出了相应的结果。

    但评论中的例子引出了一些困惑:

     1 function f1(){
     2     var n = 999;
     3     nAdd = function(){ n += 1;}
     4     function f2(){
     5         alert(n);
     6     }
     7     return f2;
     8 }
     9 var result1 = f1();
    10 var result2 = f1();
    11 
    12 result1();//999
    13 result2();//999
    14 nAdd();
    15 result1();//999
    16 result2();//1000

    按之前所述,n不是共享的么?怎么这里只有result2里的n变成了1000?发生了什么?

    这么看来一定是f1里的n发生了问题,转个弯从头开始查起

    一、当f1函数定义时发生了什么

    寄出大杀器 由ecma的官方声明大致了解到,当f1定义时,它并没有理会函数内部是什么,将{}中的内容装进[[code]]这个大口袋,等待调用。换句话说这时候它只是做了一个安静的f1,大括号内部是什么全不理会。

    二、那f1调用了,[[code]]见光了,又发生了什么

    确实当到了line9和line10这里,

    var result1 = f1();
    var result2 = f1();

    f1被调用时,n nAdd f2终于有人来认养了,三个娃儿出来哽咽的说:“终于可以吃饱饭不用被关小黑屋了”...

    那result1和result2的n为啥不一个样儿?

    领养三个娃儿的流浪汉--作用域轻咳一声:“本是我(result1)领养的n nAdd两个娃,我的二弟(result2)看着欢喜,就复制了俩娃,可惜二娃nAdd太胖复制不动,我(result1)就送我弟(result2)了...”

    言归正传,result1和result2定义在全局,且都被赋值f1(),此时实际就有了对应result1和result2的两个作用域,以及相应两个作用域内的n,而nAdd在每次调用f1()时都会重新定义,直接调用nAdd会在新的作用域内执行。这也就解释了为什么

    nAdd();

    之后为什么只有result2里的n变化了。

     下面做个简单的验证:

    function f1(){
        var n = 999;
        nAdd = function(){ n += 1;}
        function f2(){
            alert(n);
        }
        return f2;
    }
    nAdd();                   //报错,nAdd undefined,证实f1定义没理会{}内部
    var result1 = f1();
    nAdd();                   //对f1内的n操作
    var result2 = f1();
    
    result1();//1000
    result2();//999        //证实了result1和result2内的n无关
    nAdd();
    result1();//1000
    result2();//1000

    如有错误,欢迎提出,验证后一定更改。

  • 相关阅读:
    LibreOJ2302
    POJ3693
    BZOJ3697
    BZOJ2599
    BZOJ2152
    BZOJ1468
    BZOJ4653
    BZOJ4553
    BZOJ4552
    BZOJ4551
  • 原文地址:https://www.cnblogs.com/newbob/p/4565724.html
Copyright © 2011-2022 走看看