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); //2console.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();