一个闭包引发的血案

先声明一下,以下内容完全是个人经验的认识,并不保证正确,不要误导了还在茁壮成长的童鞋~

 

此事说来话长,话说从盘古开天辟的时候。。。(这你妹也太长了点儿吧。。。)

=。=!  好吧好吧,其实就是昨天,办公室里的一个师哥在研究JS的闭包,然后就追溯到了JS变量的作用域链,并且最后弄出了这样一段代码:

function makefunc(x) { 
  return function() { 
    return x; 
  }
}
var a = [makefunc(0), makefunc(1), makefunc(2)]; 
alert(a[0]()); 
alert(a[1]()); 
alert(a[2]());

结果就是分别弹出:0,1,2

 这里就看出了,makefunc这个函数每次返回的函数都是相同的,但是,返回的函数的执行环境不同,也就是说这个函数所处的作用域链是不同的。。。

当每次执行makefunc这个函数时,返回的是一个相同的匿名函数和这个匿名函数执行所需要的环境的综合体,这也就是传说中的闭包~ (主角终于登场了~)

 那么我们就可以看出,数组a的每一个元素,其实都是一个function,用a[0]()这样的方式来执行它,从而得到了上面的结果,那当我们console.log出数组a的时候(不晓得用console.log出来的结果是不是足以证明一下的结论。。。。),我们发现它的每个元素里面都带有这个function执行时需要的变量x,也就是其实在a数组中的每个元素都是有他的完整的一套执行代码和运行空间,也就是闭包的真面目。。。。。

那然后呢,我们俩个有继续巴拉巴拉。。。。。  说道作用域,又说道JS代码在执行时变量的存储和回收,于是就出现了下面这段代码:

var a = 10;
function b(){
    a = 3;
    function a(){}
}
b();
alert(a);

嘿嘿,看官们觉的这段代码的弹出结果是什么捏?

function ? 不对~   3 ?  不对~  是10~!

有木有,它竟然是10~! 你让函数里面那两个a情何以堪啊~

那这是为什么捏? 其实还是比较简单的,是因为js在执行前,会先扫描一下全文,把用到的变量先在作用域的开头做一次声明,也就是我们看到的function a(),它的作用域是整个b函数,我们也知道

function a(){} 和 var a = function(){} 是一样的,所以其实上面的代码在js的执行顺序是这样的

var a = 10;
function b(){
    var a ;
    a = 3;
    a = function(){};
}
b();
alert(a);

亲们,这下看出来了吧,函数里面的变量a在函数执行完后被回收,所以,下面的弹窗是显示的最开始的a的值。。。。。

额,好吧,总觉得js的这个做法有些坑,但是还挺好玩的~

那么,现在我们弄明白了js的作用域、作用域链以及传说中强大的闭包,那么我们就写个封装在闭包里的函数吧~

(function(){
  .........
})();

诶~ 诶~ 诶~ 等会儿~ function外面的那个小括号是干什么滴捏?

封装闭包呀~封装闭包为什么要有一个小括号捏?话说没有那个小括号的话,function就不是闭包了?这个小括号在这里到底起了什么作用捏?(。。。。。  这。。。。  我还以为要结束了呢,怎么又来这么多问题?!)(所以才说是引发的“血案”啊~)

好吧,那就再看看这个传说中的小括号吧~

那么首先我们知道:

(fucntion(){alert(1);})();

这样写的话,里面的匿名function是会被执行的,那么当我们把小括号去掉呢?  

function(){alert(1);}();
好吧,我承认他执行不了。。。 = =!

话说那去掉括号后要怎么样才会执行呢? 很明显给它加函数名调用嘛~

function a(){alert(1);};
a();
额,好吧,那话说我加上括号的话,再这样调用呢?

(function a(){alert(1)});
a();
哎呦喂~  竟然提示说a未定义~  这。。。。。

那我们把里面的函数赋给一个全局变量会怎么样呢?

var a;
(a = function(){alert(1);});
a();
好吧,它执行了也就是说原来的代码在小括号作用完成后,里面的a被回收了。。。。

经过翻阅资料,发现这里的小括号的作用是强制表达式运算,那么,也就是说它会让里面的表达式强制性进行一遍运算~

那么,大概可以猜测上面的小括号的作用应该是类似于下面的代码

function (){
  return function (){alert(1);};
}
也就是说小括号运算结束后,把里面的a函数以匿名函数的方式返回回来,而返回的匿名函数实际上就是一个有执行代码和执行环境的一个闭包,这样,也就是实现了把方法封装到一个闭包里了。。。。

然后放出两个查到的资料:

JS小括号的作用

JS声明变量的原理

 

然后捏,上一张”闭包“的果照~(哇哈哈哈哈哈~)

 

 

哇哈哈哈哈~  很上镜哦~

 

 

最后,惯有的唠叨几句:

话说再过两天就要回家了呀~  小心情还是很鸡冻滴~  还是觉的这个寒假要好好珍惜,嗯嗯~  多的就先不啰嗦了,等回家有时间再说吧~  嗯嗯,今天就到这里吧~  

对了~  我觉得我得求一份工作了~  六月份就毕业了,o(︶︿︶)o 唉~  桑不起呀~  

好了好了,就到了这了,还是祝大家都开心哈~

标签: js, 闭包

暂无评论

  1. 文章不错 ,欢迎互踩 哈哈

添加新评论

icon_question.gificon_razz.gificon_sad.gificon_evil.gificon_exclaim.gificon_smile.gificon_redface.gificon_biggrin.gificon_surprised.gificon_eek.gificon_confused.gificon_cool.gificon_lol.gificon_mad.gificon_twisted.gificon_rolleyes.gificon_wink.gificon_idea.gificon_arrow.gificon_neutral.gificon_cry.gificon_mrgreen.gif