According to the MDC,ECMA-262,第5版将forEach实施为:
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisp, t[i], i, t);
}
};
}
有人能告诉我“var t = Object(this)”这行是做什么的吗?对象(这个)与普通的不同之处是什么?在这里做的差异是什么工作?
答案 0 :(得分:16)
Mozilla实现只是尝试模拟规范中描述的步骤,Object(this);
模拟第一步,调用ToObject
内部方法:
来自Array.prototype.forEach
15.4.4.18:
...
调用forEach方法时 一个或两个参数,如下 采取的步骤:
让O成为召唤的结果 ToObject传递此值作为 参数。
让lenValue成为使用参数“length”调用O的[[Get]]内部方法的结果。
- 醇>
设len为ToUint32(lenValue)。
...
在幕后调用the Object constructor as a function内部进行类型转换,如15.2.1.1中所述调用ToObject
方法。
如果你仔细观察,还有更多这样的事情,例如,行:
var len = t.length >>> 0;
他们使用无符号右移运算符(ToUint32)模拟对>>>
内部方法的调用,如步骤3中所述。
修改强> 前面的行回答了为什么 Mozilla实现以这种方式实现它。
你可能想知道为什么ECMAScript规范。我需要致电ToObject
,查看第2步,这看起来很明显:
- 让lenValue成为使用参数“length”调用O的[[Get]]内部方法的结果。
醇>
规范。需要确保调用函数时使用的this
值是一个对象,因为原始值没有任何内部方法,正如您在步骤2中看到的那样,需要[[Get]](P)
内部方法来获取length
属性的值。
这样做是因为对于严格函数(以及内置函数),您可以将原始值设置为函数的this
值,例如:
(function () {"use strict"; return typeof this; }).call(5); // "number"
对于非严格函数,this
值始终转换为Object:
(function () { return typeof this; }).call(5); // "object"
答案 1 :(得分:3)
可能的原因是s9.9 ECMA-262,关于抽象 ToObject
操作(如@CMS所述)。
当null
或undefined
值被调用时,它会强制抛出TypeError
,但这些已被前一行捕获。
但是如果你打电话:
Array.prototype.forEach.call("123", func() { ... } )
如果不是类型强制,这将失败。特别是如果index in this
是this
,则您无法致电string
,但可以 在 ToObject
的结果上调用它
15.4.4.18中的这段文字可能很重要:
forEach函数是故意通用的;它不要求它的这个值是一个Array对象。因此,它可以转移到其他类型的对象以用作方法。 forEach函数是否可以成功应用于宿主对象是依赖于实现的。
答案 2 :(得分:0)
我一直在写var t = this;
。我发现它的范围有时依赖于浏览器;在任何情况下,当范围发生变化时,并不总是清楚浏览器将使用关键字做什么,特别是在方法闭包中。我喜欢将我的JS代码愚蠢到幼儿园级别,为个人浏览器留下最小的空间来做奇怪的事情。
为了确保在将this
传递给某个方法或其他内容时,我总是要处理我想要处理的this
,我总是先写var t = this;
作为第一个我的方法的一行。然后,t
是一个变量并遵循可预测的变量范围规则,并且在指定时将其指针分配给此时由此表示的对象。这样我就不必担心方法,其他对象或不合规的浏览器重新解释this
在范围内引用的内容。