为什么 `typeof this` 返回 "object"?

9
var f = function(o){ return this+":"+o+"::"+(typeof this)+":"+(typeof o) };
f.call( "2", "2" );
// "2:2::object:string"

var f = function(o){ return this+":"+(typeof this)+":"+(typeof o); };
var x = [1,/foo/,"bar",function(){},true,[],{}];
for (var i=0;i<x.length;++i) console.log(f.call(x[i],x[i]));
// "1:object:number"
// "/foo/:object:object"
// "bar:object:string"
// "function () {\n}:function:function"
// "true:object:boolean"
// ":object:object"
// "[object Object]:object:object"

我在Chrome,Firefox和Safari中看到了相同的结果,因此我认为这是按照规范定义的,但是......为什么呢?规范中是在哪里定义的?为什么函数没有呢?


哇,从来不知道那个。现在我也想知道为什么! - Matt
1个回答

11

根据ECMA-262 ECMAScript语言规范第三版中的定义(请参见脚注),它基于该规范(第15.3.4.4节):

var result = fun.call(thisArg[, arg1[, arg2[, ...]]]);  

参数

thisArg

确定fun内的this的值。如果thisArg为null或undefined,则this将是全局对象。否则,this将等于Object(thisArg)(如果thisArg已经是一个对象,则为thisArg;如果thisArg是对应类型的原始值(String、Boolean或Number),则为包含该原始值的Object)。因此,在函数执行时,typeof this始终为"object"。

特别注意最后一行。

关键的是,JavaScript的原始值(stringnumberbooleannullundefined)是不可变的,所以无法向它们附加函数。因此,call函数将原始值包装在Object中,以便可以附加函数。

例如:

以下代码无效:

var test = "string";
//the next 2 lines are invalid, as `test` is a primitive 
test.someFun = function () { alert(this); }; 
test.someFun();

有效:

var test = "string";
//wrap test up to give it a mutable wrapper
var temp = Object(test);
temp.someFun = function () { alert(this); };
temp.someFun();

(注脚) - 如Patrick dw在评论中指出的,当在严格模式下时,以下情况将会有所改变:ECMA-262 ECMAScript语言规范第5版

 

来自第15.3.4.4节:

   
    

注意:thisArg的值作为this值传递,不进行任何修改。 这是从第3版开始的变化,在第3版中,未定义或null的thisArg将被替换为全局对象,并对所有其他值应用ToObject函数,并将结果作为this值传递。

 

3
请注意,这在ECMAScript 5中已经改变。来自第15.3.4.4节:注意,thisArg值作为this值传递时不会被修改。这是从第3版开始的变化,其中未定义或空的thisArg将被替换为全局对象,并且ToObject将应用于所有其他值,并将该结果作为this值传递。 - user113716
啊哈,这让我们在 ECMAScript-262 rev3 规范的正确轨道上了。第15.3.4.4节说:“如果_thisArg_为nullundefined,则调用的函数将全局对象作为this值传递。否则,调用的函数将以ToObject(thisArg)作为this值传递。” ToObject运算符在第9.9节中有描述。基本上,使用数字进行call操作就像传递new Number(42)一样,其typeof"object"。谢谢! - Phrogz
@patrickdw 很高兴听到这个变化的好消息,感谢您的提醒! - Phrogz
@Phrogz - 不用谢。我还应该注意到,新行为适用于新的“严格”模式。否则,将应用原始行为。这在第10.4.3节输入函数代码中有详细说明。 - user113716
1
@patrick dw,解释得很清楚,我已经将您的注释添加到答案中。 - jball

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接