【译】JavaScript进阶 从实现理解闭包

来源于 现代JavaScript教程
闭包章节
中文翻译计划
本文很清晰地解释了闭包是什么,以及闭包如何产生,相信你看完也会有所收获

关键字 Closure 闭包 Lexical Environment 词法环境 Environment Record 环境记录

闭包(Closure)

JavaScript 是一个 function-oriented 的语言。这带来了很大的操作自由。函数只需创建一次,可以拷贝到另一个变量,或者作为一个参数传入另一个函数然后在一个全新的环境调用。

我们知道函数可以访问它外部的变量,这个 feature 十分常用。

但是当外部变量改变时会发生什么?函数时获取最新的值,还是函数创建当时的值?

还有一个问题,当函数被送到其他地方再调用……他能访问那个地方的外部变量吗?

不同语言的表现有所不同,下面我们研究一下 JavaScript 中的表现。

两个问题

我们先思考下面两种情况,看完这篇文章你就可以回答这两个问题,更复杂的问题也不在话下。

  1. sayHi 函数使用了外部变量 name。函数运行时,会使用两个值中的哪个?

    let name = "John";
    
    function sayHi() {
      alert("Hi, " + name);
    }
    
    name = "Pete";
    
    sayHi(); // "John" 还是 "Pete"?
    复制代码

    这个情况不论是浏览器端还是服务器端都很常见。函数很可能在它创建一段时间后才执行,例如等待用户操作或者网络请求。

    问题是:函数是否会选择变量最新的值呢?

  2. makeWorker 函数创造并返回了另一个函数。这个新函数可以在任何地方调用。他会访问创建时的变量还是调用时的变量呢?

    function makeWorker() {
      let name = "Pete";
    
      return function() {
        alert(name);
      };
    }
    
    let name = "John";
    
    // 创建函数
    let work = makeWorker();
    
    // 调用函数
    work(); // "Pete" (创建时) 还是 "John" (调用时)?
    复制代码

Lexical Environment (词法环境)

要理解里面发生了什么,必须先明白“变量”到底是什么。

在 JavaScript 里,任何运行的函数、代码块、整个 script 都会关联一个被叫做 Lexical Environment (词法环境) 的对象。

Lexical Environment 对象包含两个部分:(译者:这里是重点)

  1. Environment Record (环境记录)是一个拥有全部局部变量作为属性的对象(以及其他如 this 值的信息)。
  2. *outer lexical environment (外部词法环境)*的引用,通常词法关联外面一层代码(花括号外一层)。

所以,“变量”就是内部对象 Environment Record 的一个属性。要改变一个对象,意味着改变 Lexical Environment 的属性。

例如在这段简单的代码中,只有一个 Lexical Environment:

这就是所谓 global Lexical Environment (全局语法环境),对应整个 script。对于浏览端,整个

你可能感兴趣的:(javascript,前端,面试,ViewUI)