变量对象(函数创建过程生成)
关键字:静态作用域链,AO
Javacript是静态作用域链,也就确定了对变量查找的访问权限,是在被定义的时候就确定好的,也就是函数的作用域在函数定义的时候就决定了在,这个时候会生成变量对象AO,保存在下面所说的scope中。
函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,可以理解成 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!
函数创建的时候,保存的是根据词法所生成的作用域链,执行的时候,会复制这个作用域链,作为自己作用域链的初始化,然后根据环境生成变量对象,然后将这个变量对象,添加到这个复制的作用域链,这才完整的构建了自己的作用域链。至于为什么会有两个作用域链,是因为在函数创建的时候并不能确定最终的作用域的样子,为什么会采用复制的方式而不是直接修改呢?应该是因为函数会被调用很多次吧。
静态作用域链详解
执行上下文(函数执行过程)
当javascript解析到可执行代码(全局代码、函数代码、eval代码)时,会创建执行上下文。
关键字:变量提升,VO,AO
每个执行上下文都有三个重要概念:
变量对象(AO),作用域链(Scope Chain),this
进入执行上下文后(也就是函数执行的时候),会先后把arguments对象,函数的形参,函数内声明的变量和函数放到AO中。
VO = 函数声明 + 变量声明
并且,变量声明是不影响函数声明的
function test() {
console.log(inner);
function inner() {}
var inner = 12;
}
test();
输出:f inner
AO = arguments + function parameters + VO
并且,VO的声明是不影响前两者的。
function test2(a) {
console.log(a);
var a = 13;
}
test2(function() {})
输出: f()
作用域链的理解
在创建函数的时候,根据词法作用域,会初始化函数的[[scope]],存放函数父级的作用域链,在执行函数的时候,会创建函数的执行上下文,依次初始化函数的arguments对象,形参,函数内部的变量和函数,再加上之前初始化的[[scope]]构成了完整的函数作用域链。