一、js预编译
js是单线程,但并不是分析一行执行一行。代码执行前,会先进行预编译(会检查语法错误),然后再执行。
预编译会有:
变量提升和函数提升,函数声明优先级高于变量声明优先级。同一个执行上下文中,如果存在多个同名函数声明,后者会替换前面的。
二、执行栈
执行栈用于保存执行上下文,栈底压着全局执行期上下文,函数每次调用都创建一个新的执行期上下文,放进栈顶,函数执行完后,该执行期上下文会被移出执行栈,控制权交给栈顶的执行期上下文。
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
//执行栈情况:
ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
//执行栈情况:
ECStack.push(<checkscope> functionContext);
ECStack.pop();
ECStack.push(<f> functionContext);
ECStack.pop();
//这两段代码的执行栈运行情况不一样
三、变量对象与活动对象
函数上下文中,用活动对象(Activation Object)来表示变量对象。
变量对象是规范上或者js引擎上实现的,并不能在js环境中直接访问。进入函数执行期上下文时,变量对象被激活,成为活动对象,此时活动对象上的属性与方法才可以访问到。
进入函数执行上下文时,会创造arguments对象,并将传入的实参作为arguments对象的数组元素(arguments时类数组,一种对象,有length属性)
预编译过程:
1、找形参、变量、函数声明给oa添加属性
此时形参赋值和变量声明为undefined
2、寻找实参参数给形参赋值
3、寻找函数体声明,给AO添加函数方法。
4、执行代码