Javascript 闭包

Javascript 是一门函数式的编程语言,函数是一等公民,能作为传递参数,也可作为返回值,这样使闭包成为了可能。

作用域

说到闭包,不能不提作用域,在 javascript 中,没有块级作用域,只有函数作用域,作用域内能访问外部变量,但作用域外无法访问内部的变量

var i;
for(i=0; i<3; i++){
var i = 3;
console.log(i);
}
var a=2;
function test(){
var a = 3;
var b = 1;
console.log(a); //3
}
test();
console.log(a); //2
console.log(b); //error: b is not defined

第一个例子中 for 循环并不会形成作用域,所以只会循环一次,第二个例子中最后会报错,因为 b 的赋值是在函数作用域内的,所以外部是无法访问 b 的。

闭包

那如何在外部访问作用域内的变量?这里就要用到闭包,其实就是在函数的最后返回另外一个函数,返回的函数拥有父级函数内部变量的引用

function demo(){
var a = 0;
return function(){
return a;
}
}
var e = demo();
var x = e()//0

这里的 e 和 a 就形成了一个闭包,e 为 demo 的返回函数,而这个返回函数拥有 demo 中变量 a 的引用

闭包的坑

for(var i=0; i<3; i++){
setTimeout(function(){
console.log(i);
},100);
}

上面的代码并不会愉快的输出 0, 1, 2,而是输出三个 3 ,闭包只是拥有函数中变量的引用,而不是值,所以上面的代码中匿名函数的 i 只是外部变量 i 的引用,所以当过了 100ms 后调用匿名函数,这时循环已完成,i 的值为 3, 所以输出三个 3,修正上面的错误,我们要用到自执行函数传值

for(var i=0; i<3; i++){
(function(e){
setTimeout(function(){
console.log(e);
},100);
})(i)
}

一般情况下,函数执行完成之后,再没有价值,会被内存回收。但闭包中,返回函数一直有函数中变量的引用,执行后并不会被回收,所以不要过多的使用闭包,以至于造成内存溢出。

变量提升

var d = 0;
function func(){
console.log(d);
var d = 1;
}
func();

猜猜这段代码会输出什么日志,答案是 undefined,因为 javascript 每次执行时,都会把变量提升到作用域的顶部,以上代码会解析成这样

var d;
d = 0;
function func(){
var d;
console.log(d);
d = 1;
}
func();

上一篇

配置基于 virtualenv 的 supervisor

下一篇

Javascript 原型链与继承