JavaScript—设计模式与开发实践–第三章 闭包
- 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
- 对于 JavaScript程序员来说,闭包(closure)是一个难懂又必须征服的概念。
闭包是指有权访问另一个 函数作用域中的变量的函数 ----> 《JavaScript高级程序设计》第三版
闭包就是能够读取其他函数内部变量的函数 ------阮一峰
- 这两种解释都是易于理解的。我觉得阮一峰关于闭包的解释比较好。
总结《JavaScript—设计模式与开发实践》闭包
闭包
闭包的形成与变量的作用域以及变量的生存周期密切相关
变量的作用域
变量的作用域,指的是变量的有效范围。执行环境类型只有两种全局和局部(函数)。在函数中声明的变量就是局部变量,只有在该函数内才能访问这个变量。
var func = function(){
var a = 1;
alert(a); // 1
}
func();
alert(a); // a is not defined
在JS中,函数可以创造函数作用域,就好像:
此时的函数是一层半透明的玻璃,在函数里面可以看到外面的变量,而在函数外面无法看到看到函数里面的变量。
- 变量搜索过程:在函数中搜索一个变量的时候,如果该函数内没有声明这个变量,那么此次搜索过程会随着代码执行创建的作用域链往外层逐层搜索,一直到全局对象为止。
- 变量的搜索时从内而外而非从外到内的。
var a = 1;
var func1 = () => {
var b = 2 ;
var func2 = () => {
var c = 3;
alert(b); //2
alert(a); //1
}
func2();
alert(c); // c is not defined
}
func1();
变量的生存周期
除了变量的作用域之外,另外一个跟闭包有关的概念是变量的生存周期。
- 对于全局变量来说,全局变量的生存周期是永久的,除非我们主动销毁这个全局变量。
- 而对于在函数内用var 关键字声明的变量来说,当退出函数时,这些局部变量失去了他们的价值,他们会随着函数调用的结束而被销毁。
var func = function(){
var a = 1;
alert(a);
};
func():
退出函数(函数执行完)后局部变量a就会被销毁。
下面这个例子:
var func = function(){
var a = 1;
return function(){
a++;
alert(a);
}
}
var f = func();
f(); //2
f(); //3
f(); //4
f(); //5
- 这里就产生了一个闭包结构。
当退出函数后,局部变量a并没有消失,而是一直在某个地方存活着; - 因为当执行var f = func() 时,f 返回的时匿名函数的引用,它可以访问到func()被调用时产生的环境,而局部变量a一直在这个环境里。既然局部变量所在的环境还能被外界访问,这个局部变量就有了不被销毁的理由。这就是一个闭包结构,局部变量的声明看起来被延续了。
闭包的作用(场景)
- 封装"私有"变量
闭包可以帮助把一些不需要暴露在全局的变量封装成“私有变量“
function Person() {
var name = "asd";
var sex = "man";
// 这个变量是私有的变量。
var yinsi = "....";
return function() {
// key: value
var obj = {
name: name,
sex: sex
}
return obj;
}
}
console.log(Person()().name);
闭包面向对象设计
下面这段代码对理解面向对象设计有很大的帮助。
var extent = function(){
var value = 0;
return {
call:function(){
value++;
console.log(value);
}
}
};
var e = extent();
e.call();
e.call();
e.call();
把这段代码换成面向对象的写法
var extent = {
value : 0,
calc : function(){
this.value++;
console.log(this.value);
}
};
extent.calc();
extent.calc();
extent.calc();