美文网首页
深入之闭包

深入之闭包

作者: 明里人 | 来源:发表于2019-07-13 10:24 被阅读0次
定义

闭包是指那些能够访问自由变量的函数

什么是自由变量?

自由变量是指在函数中使用,但这个变量既不是函数参数,也不是函数局部变量

由此,闭包有两部分组成

闭包 = 函数 + 函数能够访问的自由变量

举个例子:

var a = 1;
function foo(){
  console.log(a);  // 1
}
foo();

foo 函数可以访问到变量a,变量a既不是foo函数的参数,也不是foo函数的局部变量,所以a是自由变量,形成了闭包。
《JavaScript权威指南》 中就讲到:从技术角度将,所有的JavaScript函数都是闭包。
ECMAScript中,闭包指的是:

1、从理论角度:所有的函数,在它们创建的时候将上层上下文的数据都保存起来,即使是全局变量也是如此,函数访问全局变量就相等于在访问自由变量,这时候使用全局(最外层)的作用域。
2、从实践角度:
i、即使创建它的上下文已经销毁,它仍然存在(如:父函数执行返回内部函数)
ii、在代码中引用了自有变量

分析
let scope = "global scope";
function checkscope(){
    let scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
let foo = checkscope();
console.log(foo());  // local scope

由于作用域链,foo 函数依然可以读取到 checkscope.AO(AO表示checkscope函数作用域) 的值,即使 checkscope 执行被销毁了,JavaScript 依然会让 checkscope.AO 活在内存中,foo 函数依然可以通过作用域链找到变量 scope,从而实现了闭包这个概念。

面试必考题
let data = [];
for(var i = 0; i < 3; i ++){
    data[i] = function(){
        console.log(i);
    }
}
data[0]();
data[1]();
data[2]();

答案都是 3。

先明确一下这两个概念:全局上下文:globalContext,GO表示全局作用域。AO表示函数局部作用域。

在执行到 data[0] 函数之前,此时全局上下文 GO 为:

globalContext = {
  GO: {
    data: [ ... ],
    i: 3
  }
}

当执行 data[0] 函数的时候,data [0] 函数的作用域链为:

data[0]Context = {
  Scope: [AO, globalContext.GO]
}

data[0] 的 AO 并没有 i 值,所以会从 globalContext.GO中查找,此时全局 i 为 3,所以打印结果为3.

所以改成闭包将每次循环中的 i 的值,存储到 data数组中每个对应方法中。

let data = [];
for(var i = 0; i < 3; i ++){
    data[i] = (function(i){
        return function(){
            console.log(i);
        }
    })(i)
}
data[0]();  // 0
data[1]();  // 1
data[2]();  // 2

通过使用立即执行函数将 for 循环中全局 GO 的 此时的 i 值存储在在立即执行函数中参数,并在立即执行函数中返回一个函数,此时这个函数根据作用域链就可以访问立即执行函数 AO 中的 i 值。

当执行 data[0] 函数的时候,data[0] 函数的作用域链发生了变化:

data[0]Context = {
  Scope: [AO, 匿名函数Context.AO globalContext.GO]
}

匿名函数执行上下文AO:

匿名函数Context = {
  AO: {
    i: 0
  }
}

闭包的应用:

可通过立即执行函数实现属性私有化

闭包的防范:

闭包会导致多个执行函数公用一个共有变量,如果不是特殊需要,应尽量防止这种情况发生。

相关文章

  • 闭包

    原文出处 JavaScript深入之闭包 定义 MDN 对闭包的定义为: 闭包是指那些能够访问自由变量的函数。 那...

  • 深入之闭包

    定义 闭包是指那些能够访问自由变量的函数 什么是自由变量? 自由变量是指在函数中使用,但这个变量既不是函数参数,也...

  • JavaScript深入之闭包

    已离开简书,原因参见 http://www.jianshu.com/p/0f12350a6b66。 虽人微言轻,但...

  • JavaScript深入之闭包

    MDN对闭包的定义为:闭包是指那些能够访问自由变量的函数。自由变量 是指在函数中使用的,但既不是函数参数(形参)也...

  • JavaScript深入之闭包

    JavaScript深入系列第八篇,介绍理论上的闭包和实践上的闭包,以及从作用域链的角度解析经典的闭包题。 定义 ...

  • python闭包学习

    参考文章 python闭包python闭包一步一步教你认识Python闭包深入浅出python闭包

  • python函数之闭包

    目录 python函数之闭包什么是闭包python中的namespace闭包的条件闭包的优点 python函数之闭...

  • 深入理解javascript原型和闭包[目录]

    文章地址:深入理解javascript原型和闭包 文章:深入理解javascript原型和闭包 目录列表 (不能跳...

  • 深入理解javascript原型和闭包(完结)

    深入理解javascript原型和闭包(1)——一切都是对象 深入理解javascript原型和闭包(2)——函数...

  • swift闭包学习

    闭包作为参数 参考 Swift学习之闭包

网友评论

      本文标题:深入之闭包

      本文链接:https://www.haomeiwen.com/subject/kihpkctx.html