在系列(四)中,我留下了自己的疑惑,其实我是有答案的。答案就是遵循"忽略原则"。如果不忽略整个运行机制想必会乱套。MMP
继续我的变量对象笔记记录...
为了更加深刻地理解变量对象,这回我们结合一些实例来探讨。
5.1 实例分析
//demo01
function test() {
console.log(a);
console.log(foo());
var a = 1;
function foo() {
return 2;
};
}
test();复制代码
当运行test函数时,我们说他对应的执行上下文被激活(创建)。我们知道执行上下文的生命周期有两个阶段(创建阶段和执行阶段)。在这里我们用如下形式来表达这个过程:
//创建过程
testEC = {
VO: {}, //变量对象
scopeChain: [], //作用域链
this: {}
}
//学习js是渐进增强的过程,所以这里对作用域链和this不做过多解释,目前我们只关注变量对象(VO)
VO = {
arguments: {...},
foo: <foo reference> //函数应用
a: undefined
}复制代码
在call stack中,如果当前执行上下文处于call stack的栈顶,则意味着这个执行上下文出于激活状态,此时变量对象称之为活动对象(AO, Activation Object)。活动对象包含变量对象的所有属性,并且此时所有的属性都已完成赋值(在这里就需要注意了:变量赋值是发生在执行上下文的执行阶段),除此之外,活动对象还包含了this指向。
//执行阶段
VO -> AO
AO = {
arguments: {},
foo: <foo reference>,
a: 1,
this: window
}复制代码
因此上面例子实际执行顺序为:
function test() {
function foo() {
return 2;
}
var a = undefined;
console.log(a);
console.log(foo());
a = 1;
}
test();复制代码
下面我们再来看个例子巩固一下:
//demo02.js
function test() {
consloe.log(foo);
console.log(bar);
var foo = 'Hello';
console.log(foo);
var bar = function() {
return 'world';
}
function foo() {
return 'hello'
}
}
test();复制代码
运行test函数时,对应的上下文开始创建,可以用如下形式来表达这个过程:
//创建过程
testEC = {
VO: {
arguments: {},
foo: <foo reference>,
bar: undefined
}, //变量对象
scopeChain: [], //作用域链
this: {}
}
//执行阶段
VO -> AO
AO = {
arguments: {...},
foo: 'Hello',
bar: <bar referencer>,
this: window
}复制代码
融合整个知识点,相信您变量对象已经掌握了。
5.2 全局上下文的变量对象
以浏览器为例,全局对象为window对象。
全局上下文的变量对象有一个特殊的地方,即他的变量对象就是window对象,而且全局上下文的变量对象不能变成活动对象。
除此之外,全局上下文的生命周期与程序的生命周期一致,只要程序运行不结束(比如关掉浏览器窗口),全局上下文就会一直存在,其它所有的执行上下文都能直接访问全局上下文的属性(这一点很重要)。
到这里,我的变量对象学习过程也就结束了。
记住:执行上下的生命周期、变量对象->活动对象、全局上下文的特殊性。
这些都是我以往的学习笔记。如果您看到此笔记,希望您能指出我的错误。有这么一个群,里面的小伙伴互相监督,坚持每天输出自己的学习心得,不输出就出局。希望您能加入,我们一起终身学习。欢迎添加我的个人微信号:Pan1005919589