春暖花开,又到了程序猿换领地的季节了,各大论坛出现不少的面试题和各类押题,而后我和小伙伴仔细研究,果真大部分不会。其中有一个讲zepto源码的,提到了js三座大山:闭包,原型和异步。我曾经入门的时候在这3个山里面饶了好久好久,并且屡次觉得绕出去的时候才发现我只是过了一个小山头,苦不堪言。固然,我以为如今本身已经绕出来了,那么就先讲一讲闭包这座山的路。javascript
先放一段经典的面试题java
for(var i = 0; i < 10; i ++) { bt[i].onclick = function(){ console.log(i); } }
初次接触闭包就是这个问题,可是这样看,好像和闭包没有什么关系,并且确实没有什么关系。这个每次结果都是9已经毫无疑问了,可是为何是9?咱们慢慢拆解。面试
var i; for(i = 0; i < 10; i ++) { bt[i].onclick = function(){ console.log(i); } }
i做为变量被提高了,咱们再把循环展开浏览器
bt[0].onclick = function(){ console.log(i); } bt[1].onclick = function(){ console.log(i); } bt[2].onclick = function(){ console.log(i); } ....
这时有人确定和我当年有同样的疑问,为何function里的是i,不该该对应的是当时的i的值吗?闭包
先举个例子异步
var i = 10; function test(){ var i = 1; console.log(i); }
若是i在js加载就赋值了,那么是否是就成了console.log(10)
,test()执行后打印的应该是10而不是1啊。很明显,解析js的时候,test这个函数内部并无赋值,只是给它了一个变量,具体什么值等调用了才会拿到。其实拆到这的时候我也很懵,什么鬼,为何会是这样。函数
在ES6以前是没有块级做用域这个概念的,只有全局做用域、函数做用域和eval做用域。this
在浏览器加载js脚本的时候,解析器在解析js代码时,会先进入全局做用域,若是碰到函数调用,会创造函数上下文,并将这个上下文压入到执行栈中,若是这个函数内部还有另外一个函数调用,那么就会把另外一个函数压入到执行栈的顶部,依次类推,最后调用的函数老是被放到执行栈的最顶部,而后执行最上层的函数。线程
这个过程涉及到js很重要的几个点:js是单线程,同步执行,函数被调用的时候才会建立执行上下文。code
既然知道了函数调用的时候会建立执行上下文,那么就要探究下怎么执行上下文内部怎么执行的:
上面这些步骤能够分为2个阶段:初始化阶段(建立阶段)和执行阶段。
咱们看个例子
var a = 100; function fn(n) { var a = 10; const b = function(){}; function c(o) {} }
当在调用fn(11)时,建立阶段实际上是这样的:
function fn(n) { a:100 //父级上下文中的变量(做用域链) arguments:{ 0:11, length:1 } c:function c(o) a: undefined b: undefined this:{//全局是window} }
很明显,在建立阶段只是作了属性名的定义,并无给函数内变量赋值,全局变量和参数除外。建立阶段完成后,便开始进入执行阶段。代码执行阶段看起来是这样得:
function fn(n) { a:100 //父级上下文中的变量(做用域链) arguments:{ 0:11, length:1 } c:function c(o) a: 10 b: function() this:{//全局是window} }
这就是整个执行环境。
说了这么多废(pu)话(dian),终于到正题了。红皮书是这样说的:闭包是有权访问另外一个函数做用域中的变量的函数。若是熟读红皮书的话应该很好理解这句话,主要在做用域链那。固然通俗点就是内部能够访问外部,外部不能访问内部。
如今返回去看看那道经典的题目,应该很好解决了。根据执行上下文的过程,咱们在外层加一个函数,而且执行它,由于初始化过程当中参数是能够直接被赋值的。
for(var i = 0; i < 10; i ++) { (function(num){ bt[i].onclick = function(){ console.log(num); } })(i) }
这样就ok了。
闭包并不可怕,只要搞清js的一些执行机制,不少也就迎刃而解了。当时我并不理解为何要加一个理解执行函数,后来看到不少关于做用域链和执行上下文的文章,反过来想一想,也就没什么难的了。固然,闭包一个很重要的做用就是设置私有变量,其实这个题目也算一个。
这个讲的很简单,若是仔细说闭包,估计要说2小时。这个只是来理解这一个题目而已。
他的原创之处并不优秀,他的优秀之处并不是原创!!!