JavaScript 闭包介绍
闭包是JS学习过程中的难点之一,本文主要介绍一下对闭包的认识。
- JS中变量的作用域;
要理解闭包,先要理解JS中变量的作用域,变量作用域有两种:局部变量和全局变量,JS特殊之处在于,函数内部可以直接读取全局变量。
var name="global"; function foo() { alert(name); } foo();
反之,从外部访问函数的局部变量则不行
function foo() { var fun_name = "foo"; // 这里需要注意的是,变量的定位之前如果不加上var的话,fun_name会被作为全局变量对待 } foo(); fun_name; // undefined
- 如何从外部读取局部变量;
上面已经介绍过,正常情况下是无法从函数的外部获取到函数内部变量的值的,但是有些情况下这种需求又确实存在,所以需要做一下变通,具体的变通方式请看下面的例子:
function foo() { a=100; return function() {return a;} } bar=foo(); bar();
- 闭包的概念;
上面的例子中,函数 foo 内部的匿名函数就是闭包,简单来说,能够读取其他函数内部变量的函数就是闭包,由于在JS中, 只有其他函数内部的子函数才能读取到函数的局部变量,所以可以认为闭包就是子函数。
- 使用闭包的注意点;
使用必要有两个地方要注意:
1. 闭包会导致函数调用完成后,局部变量仍然不被垃圾回收机制回收,所以可能会导致内存溢出,最好的方法是在变量使用完成后,手动清空不在需要的变量,比如 bar=null;
2. 由于子函数内部可以操作外部函数的局部变量,这个地方要特别注意不要误操作;
- 思考题;
对比一下两段代码的输出,有助于理解闭包:
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
这断代码中,由于子匿名函数内部并没有定义this指针,所以沿着作用域链向上会找到全局的this指针,全局的this指针对应的name变量的值就是"The Window"
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
这段代码中,子匿名函数中没有定位that变量,沿着作用域链向上找,找到 getNameFunc 函数,这个函数中定义了 that 变量,that变量的值为指向 object 对象的指针,所以此时 that.name 返回object 对象的name属性。
参考资料:
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html