函数的编译和执行

全局函数的编译

  1. 在js引擎编译的时候,如果检测到是一个函数:
    (1) 会在Global Object先声明一个函数的变量
    (2) 之后在内存中创建一个新的空间存储函数对象
    (3) 函数对象里包含着(父级作用域、函数代码执行块和this),GO里的函数变量则引用着这个新地址

注意: foo()是执行代码,编译时是不会执行的

函数的执行

  1. 执行函数调用时( foo() ),会在全局调用栈中(GEC)创建一个函数执行上下文(FEC)
    (1) 函数执行上下文和全局执行上下文一样,也会创建一个内部变量VO,指向每个函数的AO[Activation Object](活跃对象)
    (2) AO相当于函数内的GO,与GO相同的逻辑,将函数里的形参和声明的变量存放在一个对象里
    (3) 之后开始调用函数内的执行代码
    (4) 当函数调用完成后,执行改函数的FEC会从调用栈释放,同时在GO创建的函数内存也会被释放

注意: 函数的作用域跟它定义的位置有关系,跟它调用的位置没关系
备注: 一个函数多次调用互相不受影响的原因就是因为每次GO在调用函数上下文执行栈时,都会创建一个新的AO存储函数里的形参和声明的变量/函数

作用域链(scope chain)

  1. Q:什么是作用域链?
    A:scopechain = VO + ParentScope (VO和父级作用域)
    父级作用域在JS代码编译时就被确定了,就是函数地址中存放的parentscope
    函数执行时,当定义的变量在VO中查找不到,会根据scope chain中的parent scope向上查找,直到全局作作用域

补充

  1. ECMA最新标准中,将VO的概念重新解释为VE(Variable Environment)[环境变量],是将变量作为一条环境记录绑定在环境中,不一定非要是一个对象做数据集合(也可以是HashMap或其它)

  2. JS在编译时,会将没用关键字声明的变量放到GO里

    var a = b =10
    // 解析为
    var a = 10
        b = 10
    // 先执行b的赋值

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!