最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 温故而知新 - 重新认识JavaScript的Execution Context

    正文概述 掘金(文之)   2021-04-06   482

    更新下相关知识,立足过往,拥抱未来。

    概念

    直接看规范关于ExecutionContext的定义:

    ExecutionContext为抽象概念,用来描述可执行代码的执行环境。可执行代码的运行,都是在ExecutionContext中。

    管理方式ExecutionContextStack

    Execution context Stack为后进先出(LIFO)的栈结构。栈顶永远是running execution context。当控制从当前execution context对应可执行代码转移到另一段可执行代码时,相应的execution context将被创建,并压入栈顶,执行结束,对应的execution context从栈顶弹出。

    思索:什么ECMAScript特性会使Execution context stack不遵循LIFO规则?

    规范里面提到:

    然后在规范里面,并没有找到some ECMAScript features到底是什么特性。不过,第一反应,Generator算不算?在stackoverflow上,有这么一个讨论Execution Context Stack. Violation of the LIFO order using Generator Function

    function *gen() {
      yield 1;
      return 2;
    }
    
    let g = gen();
    
    console.log(g.next().value);
    console.log(g.next().value);
    

    调用一个函数时,当前execution context暂停执行,被调用函数的execution context创建并压入栈顶,当函数返回时,函数execution context被销毁,暂停的execution context得以恢复执行。

    现在,使用的是GeneratorGenerator函数的execution context在返回yield表达式的值之后仍然存在,并未销毁,只是暂停并移交出了控制权,可能在某些时候恢复执行。

    究竟是不是呢?有待求证。

    词法环境Lexical Environments

    看规范的定义:

    按规范来说,Lexical Environment定义了标识identifiersVariablesFunctions的映射。

    组成 Lexical Environment包含两部分:

    • Environment Record

    记录被创建的标识identifiersVariablesFunctions的映射

    类型简述
    Declarative Environment Records记录 varconstletclassimportfunction等声明Object Environment Records与某对象绑定,记录该对象中string identifier的属性,非string identifier的属性不会被记录。Object environment recordswith语句所创建Function Environment RecordsDeclarative Environment Records的一种,用于函数的顶层,如果为非箭头函数的情况,提供this的绑定,若还引用了 super则提供super方法的绑定Global Environment Records包含所有顶层声明及global object的属性,Declarative Environment RecordsObject Environment Records的组合Module Environment RecordsDeclarative Environment Records的一种,用于ES module的顶层,除去常量和变量的声明,还包含不可变的import的绑定,该绑定提供了到另一environment records的间接访问
    • 外部Lexical Environment的引用

    通过引用构成了嵌套结构,引用可能为null

    分类 Lexical Environment分三类:

    • Global Environment

    没有外部Lexical EnvironmentLexical Environment

    • Module Environment

    包含了模块顶层的声明以及导入的声明,外部Lexical EnvironmentGlobal Environment

    • Function Environment

    对应于JavaScript中的函数,其会建立this的绑定以及必要的super方法的绑定

    变量环境Variable Environments

    在ES6前,声明变量都是通过var声明的,在ES6后有了letconst进行声明变量,为了兼容var,便用Variable Environments来存储var声明的变量。

    Variable Environments实质上仍为Lexical Environments

    机制

    具体可以参考规范ECMAScript 2019 Language Specification。相关的是在8.3 Execution Contexts

    一篇很不错的文章参考Understanding Execution Context and Execution Stack in Javascript, 该文章的中文翻译版中文版

    参考里面的例子:

    var a = 20;
    var b = 40;
    let c = 60;
    
    function foo(d, e) {
        var f = 80;
        
        return d + e + f;
    }
    
    c = foo(a, b);
    

    创建的Execution Context像这样:

    GlobalExecutionContext = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          c: < uninitialized >,
          foo: < func >
        }
        outer: <null>,
        ThisBinding: <Global Object>
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          // Identifier bindings go here
          a: undefined,
          b: undefined,
        }
        outer: <null>, 
        ThisBinding: <Global Object>
      }
    }
    

    在运行阶段,变量赋值已经完成。因此GlobalExecutionContext在执行阶段看起来就像是这样的:

    GlobalExecutionContext = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          c: 60,
          foo: < func >,
        }
        outer: <null>,
        ThisBinding: <Global Object>
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          // Identifier bindings go here
          a: 20,
          b: 40,
        }
        outer: <null>, 
        ThisBinding: <Global Object>
      }
    }
    

    当遇到函数foo(a, b)的调用时,新的FunctionExecutionContext被创建并执行函数中的代码。在创建阶段像这样:

    FunctionExecutionContext = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          Arguments: {0: 20, 1: 40, length: 2},
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>,
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          f: undefined
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>,
      }
    }
    

    执行完后,看起来像这样:

    FunctionExecutionContext = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          Arguments: {0: 20, 1: 40, length: 2},
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>,
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          f: 80
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>,
      }
    }
    

    在函数执行完成以后,返回值会被存储在c里。因此GlobalExecutionContext更新。在这之后,代码执行完成,程序运行终止。

    总结

    ECMAScript规范是年年都在更新,得与时俱进的加强学习,立足过往及当下,拥抱未来!

    参考资料

    1. 所有的函式都是閉包:談 JS 中的作用域與 Closure
    2. JS夯实之执行上下文与词法环境
    3. 结合 JavaScript 规范来谈谈 Execution Contexts 与 Lexical Environments
    4. You-Dont-Know-JS 2nd-ed
    5. ECMAScript 2019 Language Specification
    6. Understanding Execution Context and Execution Stack in Javascript

    起源地下载网 » 温故而知新 - 重新认识JavaScript的Execution Context

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元