从这可以看出详细了解执行上下文极为重要,因为其中涉及到了变量对象,作用域链,this等很多人没有责任你们弄明白,但是却极为重要的概念,它关系到我们能不能真正理解javascript。在后面的文章中我们会一一详细总结,本文的核心是变量对象。
变量对象(variable object) 变量对象的创建,依次经历了以下几个过程。 //这里a为属性名,20是属性值 { a:20 }
一、建立arguments对象:检查当前上下文中的参数,建立该对象下的属性与属性值
函数参数
二、检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用
三、检查当前上下文的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined
如果变量与函数同名,则在这个阶段,以函数值为准
console.log(foo);//function foo function foo(){console.log('function foo')} var foo=20;
//上面的执行顺序为
//首先将所有函数声明放入变量对象中 function foo(){console.log('function foo')} //其次将所有变量声明放入变量对象中,但是因为foo已经存在同名函数,此时以函数值为准,而不会被undefined覆盖 //var foo=undefined;
//然后开始执行阶段代码的执行 console.log(foo);//function foo foo=20;
根据这个规则,理解变量提升就变得十分简单了。在很多文章中虽然提到了变量提升,但是具体是怎么回事还真的很多恶人说不出来,以后在面试中变量对象的创建过程跟面试官解释变量提升,简直逼格满满。 在上面的规则中我们可以看出,function声明会比var声明优先级更高。为了帮助大家更好地理解变量对象,我们结合一些简单的例子来进行探讨。 //demo01 function test(){ console.log(a); console.log(foo());
var a=1;
function foo(){
return 2;
}
}
test(); 在上例中,我们直接从test()的执行上下文开始理解。全局作用域中test()时,test()的执行上下文开始创建。为了便于理解,我们用如下的形式来表示 //创建过程 testEC={ //变量对象 VO:{}, scopeChain:{} } //因为本文暂时不详细解释作用域链,所以把变量对象专门提出来说明
//VO为Variable Objection的缩写,即变量对象 VO={ arguments;{....},//注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解,我做了这样的处理 foo: //表示foo的地址引用 a: undefined }
未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后进行执行阶段的操作。
这样,如果在面试的时候被问到变量对象和活动对象有什么区别,就又可以自如的应答了,他们其实都是同一个对象,知识处于执行上下文的不同生命周期。不过只有处于函数调用栈栈顶的执行上下文中的变量对象,才会变成活动对象。
//执行阶段 VO->AO //Active Object AO={ arguments:{...}, foo:, a:1, this: Window } 因此,上面的例子demo1,执行顺序就变成了这样 function test(){ function foo(){ return 2chuangjian } var a; console.log(a); console.log(foo()); a=1; }
test();
再来一个例子,巩固一下我们的理解。 //demo2 function test(){ console.log(foo); console.log(bar);
var foo='Hello';
console.log(foo);
var bar=function(){
return 'hello';
}
}
test();
//创建阶段 VO={ arguments:{...}, foo:, bar: undefined } //这里有一个需要注意的地方,var声明的变量与函数同名,以函数为准
//执行阶段 VO->AO VO={ arguments:{...}, foo:'Hello', bar: , this:Window } 需要结合上面的知识,仔细对比这个例子中变量对象从创建阶段到执行阶段的变化,如果你已经理解了,说明变量对象相关的东西都已经难不倒你了。
全局上下文的变量对象
以浏览器为例,全局对象为window。 全局上下文有一个特殊的地点,它的变量对象,就是window对象。而这个特殊,在this指向上也同样适用,this也是指向window。