本文参考博客:
1. http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
2.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures (官方的)
第一步:理解链式作用域
答:Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。 不同于块级作用域哦!
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
如上,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
第二: 对于阮老师博客的理解补充
阮老师在闭包博客中说:它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
第一点是认同的,但第二点有点不敢苟同(初生牛犊,如有错误,还请大神留言指教)。
阮老师的js代码:
function f1(){
var n=999;
nAdd=function(){n+=1} // 全局变量
function f2(){ // 局部变量
alert(n);
}
return f2;
}
var result=f1(); // 因为这里改变了f2的作用域,所以f2才一直在内存中。 作用域由(f1()内部变量 ——》f1()平级)。
result(); // 999
nAdd(); // 由结果看,下面的值为1000,说明nAdd() 执行了, 因为f2作用域被改变后就一直在内存中,所以f1也一直在内存中。
result(); // 1000
// 我如果这样写,换一种方式调用,不改变f2的作用域
f1()(); // 999 执行完毕,f2的内存空间被销毁。 f1的内存空间也被销毁,nAdd虽然是全局变量,但其是方法的属性,自然也被销毁。
nAdd(); // undefined
f1()(); // 还是999
由上面我们可以提出几点疑问:
1.注意变量的访问范围和生命周期
2.方法内部的全局变量会随着方法的销毁而销毁。 注意变量的访问范围和生命周期!
3.第二种调用方式:立即执行函数。
一句话总结:
1.闭包就是能够读取其他函数内部变量的函数(是其他函数的内部函数)。
2.定义在一个函数内部的函数"。
3.闭包就是将函数内部和函数外部连接起来的一座桥梁。
4.由于js其特殊的作用域规则,要通过外部来访问函数的内部变量。 ——————闭包就是干这个的!
补充
代码理解:
function f1(){
var n=999;
nAdd=function(){n+=1;return n;} // 全局变量:都可以调用,前提是创建了-----销毁之前外部可以访问。
function f2(){
alert(n);
}
return f2;
}
alert(f1()); // 调用f1,返回f2 不调用f1都不会创建nAdd
alert(nAdd());