上一篇中是不是对引用类型不太清楚?这一篇就主要来讲一讲引用类型。
引用类型
引用类型是javascript中一种内部类型。它主要是当做一个指代,代替一个变量或者函数,当然在需要真实值时,又可以通过它寻找到真实值。
引用类型的结构
引用类型由两部分构成,一是引用类型的值指代对象的所属对象,这里我们把它叫做base,二是base中的指代对象的对象名称。用伪代码来表示:
var valueOfReferenceType = {
base: <base object>,
propertyName: <property name>
};
使用情景
引用类型的使用情景有二:
(1)在处理一个标示符时:
标示符是变量名,函数名,函数参数名和全局对象中未识别的属性名。
(2)在处理一个属性访问器时
如:
var foo = 10;
function bar( ){}
在操作的中间结果中,引用类型对应:
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
这里重点说明一下base,在javascript中所有对象或者函数都有所属对象,在每个执行上下文有个变量对象专门来管理这个执行上下文中的变量或者函数。
所以,当处理标示符时:
在全局上下文中,毋庸置疑,base === globalVO === gloabal
在函数的执行上下文中,base === VO/AO
当处理对象属性时:base === theObject
获取引用类型的真正值
一开始我们说了,引用类型只是一个指代,它并不保存真正的值。当需要真正的值时,可以通过内部一系列算法,可以得到。这个算法,我们可以用简单的伪代码来描述:
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我们也可以轻松获取引用类型的真正的值。
GetValue(fooReference); // 10
GetValue(barReference); // function object "bar"
那我们什么时候需要获取引用类型的真正值呢?
一般是在引用类型需要进行赋值、参与运算或者被调用时需要通过GetValue方法获取真正值。(注意:通过GetValue获取到的对象不再是引用类型)
引用类型与this的关系:
引用类型主要是跟函数上下文中的this指向关系密切,我们才引出引用类型来专门解释函数上下文中this的表现。
函数上下文中确定this值的规则如下:
在一个函数上下文中,this由调用者及调用者的语法形式来决定。如果调用括号()的左边是引用类型,this将设为引用类型的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。
下面我们根据调用括号左边不同分三种情况进行讨论:
(1)调用括号左边是引用类型
base对象就是this值,找到base即可。如果是全局变量下申明的,那就指向全局对象
var myObject = {
foo : function(){
console.log(this);
}
}
myObject.foo(); //毫无疑问,这个foo的base是myObject,故foo方法中的this指向myObject。
(2)调用括号左边是引用类型的值,不过这个值为null
function myFunction() {
var foo = function(){
console.log(this);
}
foo(); //AO.foo() => null.foo()
}
myFunction(); //输出:Window {top: Window, window: Window...}
当一个内部函数被调用时,这个内部函数的base应该是当前执行上下文中活动对象(OA),但是在javascript内部在OA作为base时,都当做null处理,javascript当然不允许this为null的情况发生,所有就将base设置为global对象。
(3)调用括号左边不是引用类型的值
(function () {
console.log(this); // null => global
})();
//复杂些的例子
var foo = {
bar: function () {
console.log(this);
}
};
foo.bar(); // Reference, OK => foo
(foo.bar)(); // Reference, OK => foo
(foo.bar = foo.bar)(); // global
(false || foo.bar)(); // global
(foo.bar, foo.bar)(); // global
当调用括号的左边不是引用类型而是其它类型,this自动设置为null,结果为全局对象。
第一个例子中,立即函数,它的函数调用小括号左边是一个表达式,不是一个引用。
第二个例子稍复杂的例子,我们来一个个分析:
foo.bar(),这个没有疑问,base为foo,this指向foo。
(foo.bar)(),这里用到了一个小括号,它在这起到分组符作用,它不会迫使引用类型执行GetValue方法,其执行结果,跟上面一样。
后面三个,小括号里面依次是赋值运算、或运算和逗号运算,它们都会迫使引用类型执行GetValue方法,从而返回一个函数对象。这样,函数调用小括号左边就不再是引用类型了,所有,this都是指向全局对象的。
下一篇:再也不用担心javascript的this—从代码去理解(第三篇)–关于this的典型例子
本文参考自Javascript浅谈之引用类型