前端基本功(八): javascript的变量做用域与闭包

1. 变量的做用域

  1. 变量的做用域只有两种: 全局变量与局部变量。
  2. javascript你能够在函数内部直接读取全局变量,函数外部没法读取函数内的局部变量。
  3. 若是想获得函数内部的局部变量你能够在函数内部再定义一个函数。javascript特有"链式做用域"结构。子对象会一级一级地向上寻找全部父对象的变量。因此,父对象的全部变量,对子对象都是可见的,反之则不成立。

2. 闭包

1. 闭包的定义(大多数认知)

JavaScript中的函数会造成闭包。 闭包是由函数以及建立该函数的词法环境组合而成。这个环境包含了这个闭包建立时所能访问的全部局部变量。(闭包就是可以读取其余函数内部变量的函数。在本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁。)javascript

2. 闭包实例
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(new Date, i);
    }, 1000);
}
console.log(new Date, i);
/* 结果:第 1 个 5 直接输出,1 秒以后,输出 5 个 5 Tue Mar 26 2019 11:25:19 GMT+0800 (中国标准时间) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中国标准时间) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中国标准时间) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中国标准时间) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中国标准时间) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中国标准时间) 5 */

// 若是指望代码的输出变成:5 -> 0,1,2,3,4 改造方法
1. 方案1: 匿名函数
for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
        setTimeout(function() {
            console.log(new Date, j);
        }, 1000);
    })(i);
}
console.log(new Date, i);
2. 方案2: 块级做用域
for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(new Date, i);
    }, 1000);
}
复制代码
3. 闭包的弊端

闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。html

4. 网上对闭包的定义不少,IIFE是否是闭包呢?

在requireJS出现以前,实现模块化编程主要经过IIFE,而在IIFE中常见的操做就是经过window.fn = fn来暴露接口,而这个fn就是闭包,而IIFE只是一个包含闭包的函数调用前端

(function(){
    var a = 0;
    function fn(){
        console.log(a); 
    }
    window.fn = fn;
})()
fn();

// 定义一:须要经过做用域链查找变量的函数就是闭包
var a = 2;
(function foo(){
    console.log(a);//2
})();

// 定义二: 访问上层函数的做用域的内层函数就是闭包
function foo(){
    var a = 2;
    function bar(){
        console.log(a); // 2
    }
    bar();
}
foo();

// 定义三: 在函数声明时的做用域之外的地方调用函数,须要经过将该函数做为返回值或者做为参数被传递
function foo(){
    var a = 2;
    function bar(){
        console.log(a); //2
    }
    return bar;
}
foo()();
复制代码
5. 我的认同:由于做用域链,全部函数都为闭包。
  1. 从理论角度:全部的函数。由于它们都在建立的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,由于函数中访问全局变量就至关因而在访问自由变量,这个时候使用最外层的做用域。
  2. 从实践角度:如下函数才算是闭包:1. 即便建立它的上下文销毁,仍然存在(好比内部函数从父函数返回) 2. 代码中引用了自由变量(跨了本身的做用域的变量都叫自由变量)

参考文献

  1. 学习javascript闭包
  2. 深刻理解javascript系列(16):闭包
  3. 破解前端面试:从闭包提及
相关文章
相关标签/搜索