什么是闭包
闭包是指有权访问另一个函数作用域变量的函数
闭包的作用
- 解决变量私有化
- 起到局部变量的作用
- 有全局变量的的生命周期
闭包的使用
实现一个方法,第一次执行打印 1,之后每次执行打印的结果加一
1
2
3
啥也不多想的,先实现:
var counter = 0; // counter 放在了方法外面
function add(){
counter++;
console.log("counter = " + counter);
}
add(); // 执行
add();
// ...
但是,我们希望这个方法是个独立方法,不想还有变量定义在外面。
我们换种写法:
function add(){
var counter = 0; // 局部变量
plus = function(){ // 此处才真正有效 需要调用这个方法
counter++; // 伪全局变量,有全部变量的生命周期
console.log("counter = " + counter);
}
}
add(); // 先调用add()初始化
plus(); // plus 没有加 var,是全局函数
// ...
// 注意外面不能直接访问counter,counter是局部变量
以下是重点!
上面定义了两个全局方法,再优化一下:
function add(){
var counter = 0; // 局部变量
var plus = function() { // 此处才真正有效 需要调用这个方法
counter ++; // 伪全局变量,有全部变量的生命周期
console.log("counter = " + counter);
}
return plus; // 注意这里
}
var plus = add(); // 前面方法中定义的 plus 是局部的,这里调用 add 后返回的值赋给另一个变量,可以是其他名字
plus();
plus();
// ...
实际上,上面就用了闭包(想想闭包的定义,外部的 plus 有权访问 add 的 counter)
var 个 plus,再 return 好像有些多此一举,简写:
function add(){
var counter = 0; //局部变量
return function() { // 没有再定义多余的变量
counter++; // 伪全局变量 有全部变量的生命周期
console.log("counter = " + counter);
}
}
(add())();
// 函数的立即执行:
// 函数声明(也就是执行add(),得到了一个匿名函数)和函数执行(执行这个匿名函数)放在一起
// 注意:直接这样,每次都执行 add() ,counter 又每次都重新赋值 0
用函数表达式解决,得到闭包典型的写法:
var plus = (function() {
var counter = 0; //局部变量
return function(){ // 此处才真正有效 需要调用这个方法
counter ++; // 伪全局变量 有全部变量的生命周期
console.log("counter = " + counter);
}
})();
plus(); // 第一次执行后得到了一个匿名函数
plus();
// ...
tip: 可以通过下面这样,模仿块级作用域
(function(){
// 这里是块级作用域
})()
闭包的特点
- 嵌套结构的函数
- 内部函数访问了外部函数的变量
- 在外部函数的外面,调用内部函数
// 嵌套结构的函数
var plus = (function() {
var counter = 0; //局部变量
return function(){
counter ++; // 内部函数访问了外部函数的变量期( 伪全局变量,有全部变量的生命周期)
console.log("counter = " + counter);
}
})();
plus(); // 第一次执行后得到了一个匿名函数(是内部函数)
plus(); // 在外部函数的外面,调用内部函数
// ...
闭包不一定要有return function...