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 中看到了相同的结果,所以我认为它符合规范,但是......为什么?这在规范中是在哪里定义的?为什么不用于功能?

4

1 回答 1

11

正如 ECMA-262 ECMAScript 语言规范第 3 版(见脚注)中定义的那样,它基于规范(第 15.3.4.4 节):

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

参数

thisArg

确定 this 内部 fun 的值。如果 thisArg 为 null 或未定义,这将是全局对象。否则,这将等于 Object(thisArg)(如果 thisArg 已经是一个对象,则 thisArg 或如果 thisArg 是相应类型的原始值,则为 String、Boolean 或 Number)。因此,函数执行时 typeof this == "object" 总是正确的。

特别注意最后一行。

关键是 js 原语 ( string, number, boolean, null, undefined) 是不可变的,因此不能将函数附加到它们。因此,该call函数将原语包装在 an 中,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 版的更改,其中 undefined 或 null thisArg 被替换为全局对象,并且 ToObject 应用于所有其他值,并且该结果作为 this 值传递。

于 2010-12-08T17:58:20.617 回答