闭包
闭包是函数和声明该函数的词法环境的组合
主要是由 javascript 的两个特性产生的:
- 词法作用域:内部函数可以访问函数外面的变量,是因为函数外面的变量保存在内部函数的词法作用域内,词法作用域的范围是由变量声明的位置决定,例:
function init(){
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
// 在函数内部声明的函数,词法作用域就是外层函数
function displayName(){
alert(name); // 内层函数没有name变量,在外层函数中寻找,使用父函数中声明的变量
}
displayName();
}
init();
- 函数作为值传递(
first class):也就是函数即可以作为参数传入别的函数,也可以作为别的函数的返回值
在一个函数被作为返回值返回的时候,相当于返回了一个通道,这个通道可以访问函数的词法作用域,通过词法作用域也就可以访问到外部函数的变量,即使外部函数已经销毁,这样就产生了闭包,也就是能够读取其他函数内部变量的函数。
例子
var a = function(){
var x = 1;
var fn = function(){
console.log(x);
}
fn();
return fn;
}
var b = a();
b();
执行函数 a 然后把返回值赋值给了变量 b,函数 a 的返回值是一个函数 fn ,而函数作为返回值被返回的时候,实际上是返回的一个指向 fn 的指针,最后在执行 b 函数,也就是执行 fn 函数,fn 通过词法作用域可以访问 a 中的变量 x ,所以两次执行的结果都是显示 x 的值。
特点
- 可以使得函数内部变量只能被访问,无法被修改,访问途径只能通过函数内部提供的接口
- 由于闭包产生的引用,可以使得变量不会被自动回收
大部分应用都是基于上面的特点
应用场景
- 匿名自执行函数:函数只执行一次,执行完毕立即释放资源,不会造成全局变量污染,例如ui初始化
- 结果缓存:对于某些很耗时的函数,可以通过闭包将计算结果缓存,再次调用函数的时候,如果有缓存就使用缓存,没有在重新计算
- 封装
- 实现类和继承