欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript的深入理解:变量对象(Variable Object)

程序员文章站 2023-10-29 15:20:04
通常,各类文章和javascript相关的书籍都声称:“不管是使用var关键字(在全局上下文)还是不使用var关键字(在任何地方),都可以声明一个变量”。请记住,这是错误的概...

通常,各类文章和javascript相关的书籍都声称:“不管是使用var关键字(在全局上下文)还是不使用var关键字(在任何地方),都可以声明一个变量”。请记住,这是错误的概念: 

任何时候,变量只能通过使用var关键字才能声明。

1.全局对象的属性

下面的赋值语句:

a = 10;

1

这仅仅是给全局对象创建了一个新属性(但它不是变量)。“不是变量”并不是说它不能被改变,而是指它不符合ecmascript规范中的变量概念,所以它“不是变量”(它之所以能成为全局对象的属性,完全是因为vo(globalcontext) === global,大家还记得这个吧?)。 

让我们通过下面的实例看看具体的区别吧:

alert(a); // undefined

alert(b); // "b" 没有声明

b = 10;

var a = 20;

所有根源仍然是vo和进入上下文阶段和代码执行阶段:

进入上下文阶段:

vo = {

  a: undefined

};

我们可以看到,因为“b”不是一个变量,所以在这个阶段根本就没有“b”,“b”将只在代码执行阶段才会出现(但是在我们这个例子里,还没有到那就已经出错了)。 

让我们改变一下例子代码:

alert(a); // undefined, 这个大家都知道,

b = 10;

alert(b); // 10, 代码执行阶段创建

var a = 20;

alert(a); // 20, 代码执行阶段修改

2.delete属性

关于变量,还有一个重要的知识点。变量相对于简单属性来说,变量有一个特性(attribute):{dontdelete},这个特性的含义就是不能用delete操作符直接删除变量属性。

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

但是这个规则在有个上下文里不起走样,那就是eval上下文,变量没有{dontdelete}特性。

eval('var a = 10;');

alert(window.a); // 10

alert(delete a); // true

alert(window.a); // undefined

3.活动对象的访问

特殊实现: _parent_ 属性 

前面已经提到过,按标准规范,活动对象是不可能被直接访问到的。但是,一些具体实现并没有完全遵守这个规定,例如spidermonkey和rhino;的实现中,函数有一个特殊的属性 parent,通过这个属性可以直接引用到活动对象(或全局变量对象),在此对象里创建了函数。 

例如 (spidermonkey, rhino):

var global = this;

var a = 10;

function foo() {}

alert(foo.__parent__); // global

var vo = foo.__parent__;

alert(vo.a); // 10

alert(vo === global); // true

在上面的例子中我们可以看到,函数foo是在全局上下文中创建的,所以属性parent 指向全局上下文的变量对象,即全局对象。 

然而,在spidermonkey中用同样的方式访问活动对象是不可能的:在不同版本的spidermonkey中,内部函数的parent 有时指向null ,有时指向全局对象。 

在rhino中,用同样的方式访问活动对象是完全可以的。 

例如 (rhino):

var global = this;

var x = 10;

(function foo() {

  var y = 20;

  // "foo"上下文里的活动对象

  var ao = (function () {}).__parent__;

  print(ao.y); // 20

  // 当前活动对象的__parent__ 是已经存在的全局对象

  // 变量对象的特殊链形成了

  // 所以我们叫做作用域链

  print(ao.__parent__ === global); // true

  print(ao.__parent__.x); // 10

})();