浅析闭包

422 阅读3分钟

什么是闭包

闭包是指有权访问另一个函数作用域变量函数

闭包的作用

  • 解决变量私有化
  • 起到局部变量的作用
  • 有全局变量的的生命周期

闭包的使用

实现一个方法,第一次执行打印 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...