• 执行上下文


    本文转载:https://www.qianduan.net/js-the-hardcore-execution-context/

    放在这里,只是为了查看方便

    先看个例子:

    console.log(a)  
    console.log(foo())  
    var a = 'hello world'
    
    function foo() {  
        console.log('foo')
    }

    估计大部分人早就对这种问题了如指掌了,输出结果也是脱口而出:

    undefined  
    'foo' 

    请解释一下原因?

    这不就是常说的 Hoisting 吗?

    代码在执行的时候,其实是这个样子的:

    function foo() {  
      console.log('foo')
    }
    var a
    
    console.log(a)  
    console.log(foo())
    
    a = 'hello world'  

    是的,这样解释也可以,但是不够准确。如果仅仅理解到这个层面,而不把这里面涉及到的「执行上下文」(Execution Context, 下面简称 EC)这个概念弄明白,还是不能「知其所以然」。

    首先需要澄清的一点是,像 C 和 Java 这类所谓的「静态语言」需要编译后才能运行,但其实 Javascript 一样也是有编译过程的, 只是处于一些限制,编译过程特别快(以微秒计),以至于感觉上 Javascript 代码好像并没有经过编译。

    当需要向别人描述一件事情的经过时,往往需要把事情的前因后果以及与其相关的场景预先说明一下。 类似,EC 就是一段代码涉及到的场景,在代码运行之前,js engine 会做一些变量内存分配,代码上下文关联的准备工作,这就是 EC。 EC 是 Javascript 引擎实现的一个内部机制,不能在代码中直接访问到。

    对编程语言来说,给变量赋值,获取变量的值,是需要解决的基本问题,Javascript 当然也不例外。 EC 中会给变量分配一个存储空间,与之对应的数据结构称作 enviroment。

    当程序流程需要从当前的 EC 进入另外一个和当前上下文无关的代码片段时,会创建一个新的 EC,并被推入栈中。这就是「执行上下文栈」(Execution Context Stack),可以看作是 调用栈的镜像。由于所有的 js 代码都存在于全局环境中,所以首先会创建 「全局执行上下文」(Global Execution Context),除此之外,js 中每一次的函数调用也会生成 EC,所以栈底肯定会是 全局执行上下文。

    如果把 EC 视为作一个抽象对象,那这个对象包含了代码相关的 this、enviroment(存储标识符包括变量声明、函数声明、函数表达式的数据结构)和一个指向外部 enviroment 的指针。

    Global Execution Context

       Global Execution Context = {
            global object,
            this: global object,
            outer environment: null,
            enviroment: {
                // all the identifiers
                variable,
                function expression,
                function declaration,
            },
        }

    Function Execution Context

        Execution Context = {
            this: some value,
            outer environment: outer lexcial environment,
            enviroment: {
                // all the identifiers
                parameter,
                arguments,
                variable,
                function expression,
                function declaration,
            },
        }

    在 EC 创建之后,js engine 会开始顺序执行代码。

    /** 01 **/ var x = 'hello world'
    /** 02 **/
    /** 03 **/ function foo() {
    /** 04 **/   var y = 'hellow foo'
    /** 05 **/   console.log(y)
    /** 06 **/ }
    /** 07 **/
    /** 08 **/ console.log(x)
    /** 09 **/ foo()

    代码执行前,首先创建全局执行上下文并设置为 「当前执行上下文」(running execution context):

        Execution Context = {
            global object,
            this: global object,
            outer environment: null,
            enviroment: {
                x: undefined,
                foo,
                bar,
            },
        }

    之后,顺序执行代码,执行到 ln 01 时,给变量 x 赋值,

        Global Execution Context = {
            global object,
            this: global object,
            outer environment: null,
            enviroment: {
                x: 'hello world',
                foo,
                bar,
            },
        }

    代码执行到 ln 08 时,需要去 enviroment 中寻找 x 的值,此时为 'hello world'

    代码执行到 ln 09 时,因为是对函数的调用,会创建一个新的执行上下文,并置为「当前执行上下文」:

        foo Execution Context = {
            this: window,
            outer environment: Global.environment,
            enviroment: {
                arguments,
                y: undefined,
                bar,
            },
        }

    然后代码继续执行,到 ln 04 时,有对 y 的赋值操作,此时

        foo Execution Context = {
            this: window,
            outer environment: Global.environment,
            enviroment: {
                arguments,
                y: 'hello foo',
            },
        }

    代码执行到 ln 05 有对 y 的取值操作,y 值在当前的 enviroment 中为 'hellow foo'

    EC 栈的情况,可以参照下图「调用栈」(Call Stack)的状态:

    到这里就基本上把执行上下文的一些基本概念讲完了,其中涉及到的一些内容目前不理解没有关系,后面会慢慢解释。

  • 相关阅读:
    动画,缩放
    本地公司
    调研 公司信息
    外贸 内贸 经商
    情感 爱情 恋爱
    H5源码
    世界 生活
    标识
    Jackson
    java数据结构
  • 原文地址:https://www.cnblogs.com/old-street-hehe/p/6737906.html
Copyright © 2020-2023  润新知