一、作用域
作用域即变量和函数的可访问范围,也就是说作用域控制着变量和函数的可见性和生命周期
JavaScript的作用域分为全局作用域和局部作用域
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问
调用函数时,所有在函数内声明的变量名称都将被加入到作用域中
二、作用域链
作用域链详情参考链接
简单来说就是:变量访问,先在局部查找,找不到便会去局部外的局部找,再找不到就会去全局找
作用域链直接导致:在函数内部可以访问函数外部的变量,而函数外部却无法访问函数内部的变量
三、闭包的概念
闭包 实现了函数外部对函数内部变量的访问
四、闭包的构成
示例1:
// 在fun1外如何访问其内部变量a ?
function fun1() {
var a = 0;
function fun2() {
a++;
return a;
}
return fun2;
}
function main() {
var f2 = new fun1();
console.info("fun1.a is " + f2());
console.info("fun1.a is " + f2());
}
运行 main 函数,控制台输出结果:
fun1.a is 1
fun1.a is 2
闭包的构成条件:
1、函数内部声明函数,为方便起见,称之为“外部函数”、“内部函数”
2、内部函数要调用外部函数的局部变量并返回
3、内部函数作为外部函数的返回值返回
符合这些条件后即可在外部函数的外部访问外部函数的局部变量
四、闭包的特点
示例2:
// 在fun1外如何访问其内部变量a ?
function fun1() {
var a = 0;
function fun2() {
a++;
return a;
}
return fun2;
}
var f2 = null;
function main() {
console.info("run main..");
if (f2 == null) {
f2 = new fun1();
}
console.info("fun1.a is " + f2());
console.info("fun1.a is " + f2());
}
使用html按钮触发 main 函数,点击2次,控制台输出结果:
run main..
fun1.a is 1
fun1.a is 2
run main..
fun1.a is 3
fun1.a is 4
运行结果显示变量 a 在 main 函数返回后依然驻停在内存中而不被销毁
原因:变量 f2 是全局变量,本身是驻停内存的,f2 是函数 fun1 的返回值,即函数 fun2 本身,函数 fun2 对变量 a 存在调用
通过这种层层引用的方式,迫使 局部变量 a 持续驻停内存
总结:
1、闭包可以实现函数外部对内部变量的访问
2、闭包可以实现变量的长时的内存驻停(可以实现缓存功能)
注意:闭包增加内存开销,影响网页性能,使用不当容易导致内存泄漏
四、闭包的理解
我们类比Java类对象来看JS闭包概念:
如果把外部函数看作对象,局部变量则类似于成员变量,内部函数则类似于有参构造函数
Java对象被new 出来,只要不销毁该对象本身,其成员变量和内部函数相应的也始终驻停内存
同理 就比较好理解 闭包概念
五、闭包的应用
1、迭代器或生成器
代码有空补充。。参考链接
2、大变量的缓存
3、秒杀倒计时
4、模拟实现类与继承
参考资料
【1】《深入理解JS闭包》,链接
【2】《一分钟理解JS闭包》,链接
【3】《闭包的常见应用》,链接
【4】《Python的函数》,链接