工做中大量的使用javascript,可是却并理解闭包是什么?总感受这门语言有其隐蔽的一面,若是可以掌握将会千米大增。javascript
闭包是基于词法做用域书写代码时产生的天然结果,其实闭包在日常书写的js代码中随处可见。java
当函数能够记住并访问所在的词法做用域时,就产生了闭包,即便函数是在当前词法做用域以外执行闭包
PS:我对其的理解是当一段词法做用域的代码执行以后,js引擎会对其进行回收,以便来提升性能,可是闭包阻止了这种回收,使这段词法做用域依旧处在内存当中,当你调用词法做用域中的局部变量时,依旧存在。函数
下面咱们来看一段代码,清晰地展现了闭包:性能
function foo(){spa
var a = 2;ip
function bar(){内存
console.log(a);作用域
}回调函数
return bar;
}
var baz = foo();
baz(); //2 ----这就是闭包的效果
在 foo() 执行后,一般会期待 foo() 的整个内部做用域都被销毁,由于咱们知道引擎有垃圾回收器用来释放再也不使用的内存空间。因为看上去 foo() 的内容不会再被使用,因此很 天然地会考虑对其进行回收。 而闭包的“神奇”之处正是能够阻止这件事情的发生。事实上内部做用域依然存在,所以 没有被回收。
function wait(message) {
setTimeout( function timer() {
console.log( message );
}, 1000 );
}
wait( "Hello, closure!" );
wait(..) 执行 1000 毫秒后,它的内部做用域并不会消失,timer 函数依然保有 wait(..) 做用域的闭包。
要说明闭包,for 循环是最多见的例子。
for (var i=1; i<=5; i++) {
setTimeout( function timer() { console.log( i );
}, i*1000 );
}
正常状况下,咱们对这段代码行为的预期是分别输出数字 1~5,每秒一次,每次一个。
但实际上,这段代码在运行时会以每秒一次的频率输出五次 6。
事实上, 当定时器运行时即便每一个迭代中执行的是 setTimeout(.., 0),全部的回调函数依然是在循 环结束后才会被执行,所以会每次输出一个 6 出来。
正确的作法是,咱们要使用闭包,首先按照定义咱们要给每次循环一个词法做用域,每一个做用域都要有本身的i的值,以下:
for(var i =1; i<=5;i++){
(function(i){ //给每次循环一个独立的词法做用域
setTimeout(function(){
console.log(i);
},i*1000);
})(i);
}
固然在ES6中,能够用let声明:
for (let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}