一个题目引发的闭包、函数声明以及作用域的简单思考

在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

 

 

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

posted on 2015-06-10 14:46  _blank  阅读(365)  评论(0编辑  收藏  举报

导航