【ECMAScript-262-3】变量对象 Variable Object

JS中的VO(抽象概念)是个非常重要的概念,VO是上下文的属性,其中包含着当前上下文中的变量函数声明(注意不是函数表达式)和函数形参,用来实现变量查找。

:函数声明(Functiondeclaration->FD)指如下方式: function xxx(){}

     函数表达式(Function expression->FE) 指的是位于表达式位置(expression position)的函数,最常见方式如下:var xxx = function(){} (not a NFE(named function expression)) .后续有详细介绍。FE不影响VO。

VO是当前活动上下文(EC)的属性,还记得EC栈吧?当时用数组表示的。VO用伪代码可以表示为一个对象:VO={};

 

activeExecutionContext = {
    VO:{
        //data [var,FD,arguments]
    }
};

在JS中,每一个上下文都有一个VO,在上下文中声明变量或函数就为VO添加了新的属性。可以直接访问的VO只有全局对象(global object),其他的上下文的VO不能直接访问。

--------

不同上下文的变量对象有不同的表现,下边分述:

全局上下文中的变量对象

全局对象的定义:此对象在进入任何执行上下文前就已存在,并且只有一份,他的属性在整个程序(program)级别都能访问,他的生命周期与程序相同。

全局对象初始化时就已包含属性如:Math,String等,其中一些对象指向全局对象自身,如window。

全局上下文的变量对象 === 全局对象 : VO(globalContext) === global。

这样我们就可以理解,为什么在全局上下文中声明一个变量,就可以间接访问它。

 

函数上下文中的变量对象

函数上下文的变量对象不能被直接访问,而且在这里为了便于区分,也改了个名字:activation object(激活对象?随便怎么翻译),简称AO。AO不能直接访问到,它也一样是抽象概念。

AO在进入函数上下文时创建,在进入时他就带有一个属性arguments,这个arguments就是我们平常用的那个,它包含属性callee,length等等。

arguments需要注意的就是他与实参的对应。如下函数:

 

function xxx(x,y,z){
    //dosth...
}
xxx(1,2);

在第三个参数没有传递时,大家都知道z的值和arguments[2]的值都为undefined,但是,z与arguments[2]却由于调用没有为其传入值,而断掉了他们之间的关联:

例如为x赋值:

 

function xxx(x,y,z){
    x = 5;
    console.log(arguments[0]);//5
    //or do this
    arguments[1] = 10;
    console.log(y);//10
    //but
    z = 15;
    console.log(arguments[2]);//undefined;
    arguments[2] = 20;
    console.log(z);//15
}
xxx(1,2);

相当于没有传入参数就切断了arguments与对应的参数之间的关联。

 

处理上下文代码的阶段

包含进入上下文代码执行两个阶段。VO的形成与修改与此两阶段密切相关。

1.进入上下文

这个阶段VO要添加的属性:

a.每个形参:名字+值,如果没有传递,则为 名字+undefined

b.每个函数声明:正常创建属性,如果有同名属性,则替换之,并修改原同名属性的attributes({DontDelete},{DontEnum}这些)

c.变量声明var:名字+undefined(如果有同名形参或函数,变量声明不影响已存在的属性,FE不影响VO)

 

2.代码执行阶段

此阶段VO和AO都已有属性,只是其值可能为undefined。

此阶段属性的值会在执行中被修改。

两个经典的例子:

 

alert(x); // function 
var x = 10;
alert(x); // 10 
x = 20; 
function x() {} 
alert(x); // 20

 

if (true) {
  var a = 1;
else {
  var b = 2;
}
 
alert(a); // 1
alert(b); // undefined, 而不是 "b is not defined"

第二个例子中可以看到,b已经被添加到VO中并被赋值为undefined

 

关于变量

一直有个错误的想法,在函数中不用var定义一个变量(暂且这么称呼)就是定义了一个全局变量,并且为了这个还讨论过全局变量污染,但事实真的是这样吗?

事实却是:变量只能通过var关键字来声明!!!

 不通过var关键字声明的“变量”其实是全局对象的一个属性。

 

alert(a); // undefined
alert(b); // "b" is not defined
 
b = 10;
var a = 20;

上边的代码能说明些情况吗?

并且,使用var声明的变量会包含特性:{DontDelete},这个也经常被拿来讨论,其结果用下面代码可以表示:

 

a = 10;
alert(window.a); // 10
 
alert(delete a); // true
 
alert(window.a); // undefined
 
var b = 20;
alert(window.b); // 20
 
alert(delete b); // false
 
alert(window.b); // still 20

看清楚他们之间的区别了吗?

还有一个不影响VO的就是Eval代码中的变量声明:

 

eval('var a = 10;');
alert(window.a); // 10
 
alert(delete a); // true
 
alert(window.a); // undefined

有一点要特别注意,在Firebug中进行跟踪时,总会显示用var声明的变量是可以delete的,这可能是因为Firebug中代码的执行都是通过eval进行的。

 

参考资料:http://dmitrysoshnikov.com/ecmascript/chapter-2-variable-object/

 

 

 

posted @ 2012-05-17 16:17  lemoncolaz  阅读(156)  评论(0编辑  收藏  举报