JavaScript中,当调用一个函数时,就会有相应的一个执行环境被创建。而一个执行环境的生命周期包含两个时期
变量对象的创建,依次经历了以下几个过程。
建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
根据这个规则,理解变量提升就变得十分简单了。在上面的规则中我们看出,function声明会比var声明优先级更高一点。举个例子:
function demo(){
console.log(a); //undefind testfn(); //11 var a = 2; function testfn() { console.log(11); } }
demo();
创建过程(EC:execution context)
demoEC = {
VO: {},// 变量对象
scopeChain: {},
this: {}
}
VO 为 Variable Object的缩写,即变量对象VO
VO= {
arguments: {...}, //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解
testfn: <foo reference>, // 表示foo的地址引用
a: undefined
}
未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。(PS:这里可以看出其实变量对象和活动对象其实是指向同一个,只是处在执行环境不同生命周期)
当走到demo();时,进入执行阶段
执行阶段VO -> AO // Active ObjectAO
AO = {
arguments: {...},
foo: <foo reference>,
a: 1
}
因此,上面的例子demo,执行顺序就变成了这样
function demo() {
function testfn() {
console.log(1);
}
var a;
console.log(a);
a = 1;
}
demo() ;
function demo2() {
console.log(box);
console.log(car);
var car = "BWM";
console.log(car);
var box = function () {
console.log("box");
}
function car() {
console.log("carfn");
}
}
demo2();
创建阶段VO
VO = {
arguments:{...},
car:<car refrence>, //这里car不会被后来var car变量所覆盖,而是直接跳过
box:undefind
}
当代码走到demo2();时,VO>AO
AO = {
argument:{...},
car:"BWM",
box:<boxrefrence>
}
因此,demo2的执行顺序就变成了这样
function demo2() {
function car() {
console.log("carfn");
}
var box;
console.log(box); //undefind
console.log(car); //<car refrence>
car = "BWM";
console.log(car); //"BWM"
box = function() {
console.log("box");
}
}
demo() ;
以浏览器中为例,全局对象为window。
全局上下文有一个特殊的地方,它的变量对象,就是window对象。而这个特殊,在this指向上也同样适用,this也是指向window。
windowEC = {
VO:window,
Scope chain:{},
this: window
}
除此之外,全局上下文的生命周期,与程序的生命周期一致,只要程序运行不结束,比如关掉浏览器窗口,全局上下文就会一直存在。其他所有的上下文环境,都能直接访问全局上下文的属性。
参考链接:http://mp.weixin.qq.com/s/a_oWYwK0eI_74bMVoGLwCA
原文:http://www.cnblogs.com/xpl-blogs/p/6498828.html