一、变量的作用域
要理解js的闭包,首先要了解js的变量作用域;
(1)js的变量有两种:全局变量,局部变量;
js的局部变量只会在函数内部通过var声明产生,不是通过var声明的变量也会被当成局部变量
var a = 'a'; function myFunc() { var b = 'b'; c = 'c'; } myFunc(); console.log(a); // output: a console.log(c); // output: c console.log(b); // output: Uncaught ReferenceError: b is not defined
上面结果:a, c都能在全局访问,都是全局变量, b不能再全局访问,所以是局部变量。c虽然定义在内部,但是由于没有通过var时声明,所以是全局变量。
(2)变量的作用域
看下面的例子:
var a = 'a'; function myFunc() { var b = 'b'; console.log('inner func:', a); // a console.log('inner func:', b); // b } myFunc(); console.log(a); // output: a console.log(b); // output: Uncaught ReferenceError: b is not defined
从上面的例子可以看出,函数内部可以读取函数外部的变量,而函数外部不可以读取函数内部的变量。
二、闭包
某些情况下,需要在函数外部访问函数内部的变量,正常情况是办不到的。但是我们可以想个办法:在函数内部再定义一个函数,然后再把该函数作为返回值返回,我们就可以实现在函数的外部,读取函数内部的变量了。而作为返回值的这个函数就是闭包。
function f1() { var n = 999; function f2() { console.log(++n) } return f2; }
f2就是闭包,可以让外部访问内部函数的变量n。
有些人会有疑问,在f1中直接返回n不也可以让外部访问内部函数的变量了吗?就像下面这样:
function f1() { var n = 999; return ++n; } var result1 = f1(); // 1000 var result2 = f1(); // 1000
上面虽然能访问变量,但是n在函数执行完之后就被销毁了,没有被保存下来。但是用下面的这个方法,虽然外部函数在执行完之后被销毁了, 但是n就被保存下来了:
function f1() { var n = 999; function f2() { return ++n; } return f2; } var result = f1(); result(); // 1000 result(); // 1001 result(); // 1002
因此闭包有两个用处:(1)可以使函数外部读取函数内部的变量; (2)让函数内部的变量始终保存在内存中。
因为闭包会使函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决放法是:在退出之前, 将不使用的局部变量全部删除;