var valueOfReferenceType = {
base: <base object>,
propertyName: <property name>
};
引用类型的值仅存在于两种情况中:
1. 当我们处理一个标示符时;(when we deal with an identifier;)
2. 或一个属性访问器;(or with a property accessor.)
标示符的处理过程在 Chapter 4. Scope chain中讨论;在这里我们只需要知道,使用这种处理方式的返回值总是一个引用类型的值(这对this来说很重要)。
标识符是变量名,函数名,函数参数名和全局对象中未识别的属性名。例如,下面标识符的值:
var foo = 10;
function bar() {}
在操作的中间结果中,引用类型对应的值如下:
复制代码 代码如下:
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
为了从引用类型中得到一个对象真正的值,在伪代码中可以用GetValue方法(译者注:11.1.6)来表示,如下:
复制代码 代码如下:
function GetValue(value) {
if (Type(value) != Reference) {
return value;
}
var base = GetBase(value);
if (base === null) {
throw new ReferenceError;
}
return base.[[Get]](GetPropertyName(value));
}
内部的[[Get]]方法返回对象属性真正的值,包括对原型链中继承属性的分析。
GetValue(fooReference); // 10
GetValue(barReference); // function object "bar"
属性访问器都应该熟悉。它有两种变体:点(.)语法(此时属性名是正确的标示符,且事先知道),或括号语法([])。
foo.bar();
foo['bar']();
在计算中间的返回值中,引用类型对应的值如下:
复制代码 代码如下:
var fooBarReference = {
base: foo,
propertyName: 'bar'
};
GetValue(fooBarReference); // function object "bar"
那么,从最重要的意义上来说,引用类型的值与函数上下文中的this的值是如何关联起来的呢?这个关联的过程是这篇文章的核心。(The given moment is the main of this article.) 在一个函数上下文中确定this的值的通用规则如下:
在一个函数上下文中,this的值由调用者提供,且由调用函数的方式决定。如果调用括号()的左边是引用类型的值,this将设为这个引用类型值的base对象,在其他情况下(与引用类型不同的任何其它属性),this的值都为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。
下面让我们看个例子:
复制代码 代码如下:
function foo() {
return this;
}
foo(); // global
我们看到在调用括号的左边是一个引用类型值(因为foo是一个标示符):
复制代码 代码如下:
var fooReference = {
base: global,
propertyName: 'foo'
};
相应地,this也设置为引用类型的base对象。即全局对象。
同样,使用属性访问器:
复制代码 代码如下:
var foo = {
bar: function () {
return this;
}
};
foo.bar(); // foo
同样,我们拥有一个引用类型的值,其base是foo对象,在函数bar激活时将base设置给this。
复制代码 代码如下:
var fooBarReference = {
base: foo,
propertyName: 'bar'
};
但是,如果用另一种方式激活相同的函数,this的值将不同。
var test = foo.bar;
test(); // global
因为test作为标识符,产生了其他引用类型的值,该值的base(全局对象)被设置为this的值。
复制代码 代码如下:
var testReference = {
base: global,
propertyName: 'test'
};
现在,我们可以很明确的说明,为什么用不同的形式激活同一个函数会产生不同的this,答案在于不同的引用类型(type Reference)的中间值。
复制代码 代码如下:
function foo() {
alert(this);
}
foo(); // global, because
var fooReference = {
base: global,
propertyName: 'foo'
};
alert(foo === foo.prototype.constructor); // true
// another form of the call expression
foo.prototype.constructor(); // foo.prototype, because
var fooPrototypeConstructorReference = {
base: foo.prototype,
propertyName: 'constructor'
};
另一个通过调用方式动态确定this的值的经典例子:
复制代码 代码如下: