var valueOfReferenceType = {
base: <base object>,
propertyName: <property name>
};
引用类型的值只有两种情况:
当我们处理一个标示符时
或一个属性访问器
标示符的处理过程在下一篇文章里详细讨论,在这里我们只需要知道,在该算法的返回值中,总是一个引用类型的值(这对this来说很重要)。
标识符是变量名,函数名,函数参数名和全局对象中未识别的属性名。例如,下面标识符的值:
复制代码 代码如下:
var foo = 10;
function bar() {}
在操作的中间结果中,引用类型对应的值如下:
复制代码 代码如下:
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
为了从引用类型中得到一个对象真正的值,伪代码中的GetValue方法可以做如下描述:
复制代码 代码如下:
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值如何相关?——从最重要的意义上来说。 这个关联的过程是这篇文章的核心。 一个函数上下文中确定this值的通用规则如下:
在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。注:第5版的ECMAScript中,已经不强迫转换成全局变量了,而是赋值为undefined。
我们看看这个例子中的表现:
复制代码 代码如下:
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激活时用作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)不同的中间值。
复制代码 代码如下: