我在Fedora 19上安装了v8 v.1.14.5节点和V8 v3.14.5.9。我遇到的问题是使用thisArg
可选参数的方法,如Array.prototype.forEach
。
如果我在Chromium v33或Firefox v28上执行以下代码 - jsFiddle
var y = [1, 2, 3];
y.forEach(function (element) {
console.log(this);
}, 'hej');
我得到
的输出String {0: "h", 1: "e", 2: "j", length: 3}
String {0: "h", 1: "e", 2: "j", length: 3}
String {0: "h", 1: "e", 2: "j", length: 3}
然后是相同的代码,但是在严格模式下 - jsFiddle
var y = [1, 2, 3];
y.forEach(function (element) {
'use strict';
console.log(this);
}, 'hej');
我得到了一个输出
hej
hej
hej
根据ECMA5规范sec-function.prototype.call,这些是我期望的结果。
thisArg值未经修改即作为此值传递。这是对版本3的更改,其中未定义或null thisArg替换为全局对象,ToObject应用于所有其他值,并将结果作为此值传递。即使thisArg未经修改就通过,非严格模式函数在进入函数时仍会执行这些转换。
,例如sec-array.prototype.foreach
如果提供了thisArg参数,则每次调用callbackfn时都会将其用作此值。如果未提供,则使用undefined。
和相关的伪代码
Let funcResult be the result of calling the [[Call]] internal method of callbackfn with T as thisArgument and a List containing kValue, k, and O as argumentsList.
然而,在节点上,上述两个片段都返回
{ '0': 'h', '1': 'e', '2': 'j' }
{ '0': 'h', '1': 'e', '2': 'j' }
{ '0': 'h', '1': 'e', '2': 'j' }
任何人都可以确认这是否是我的节点环境的问题,或者这是否与节点有关?
更新:只是为了确认,在节点typeof this
的两种情况下都会返回object
。
答案 0 :(得分:3)
与V8 v3.14.5.9(及更早版本)一起安装的节点v0.10.28(最新稳定版)存在问题,但问题不是节点本身,而是V8,它有一个错误。
错误报告可在2012年8月5日发布的issue 2273中找到。
严格模式功能应该接收非强制'this'值。也就是说,'this'可以是undefined / null而不是全局对象,而是原始值而不是盒装值。
调用者函数是否处于严格模式并不重要。但是,即使要调用的函数处于严格模式,“Array.prototype.forEach”等内置函数也会错误地执行强制操作。
测试用例:
(function() {
var logger = function() {
"use strict";
console.log(this);
};
var strictCaller = function() {
"use strict";
logger.call("foo");
};
var nonStrictCaller = function() {
logger.call("foo");
};
var forEachCaller = function() {
[123].forEach(logger, "foo");
};
// call from strict function: logs primitive value
strictCaller();
// call from non-strict function: logs primitive value
nonStrictCaller();
// call through forEach: logs *boxed* value (WRONG)
forEachCaller();
})();
错误修复已于2013年4月5日在revision r14149中提交给V8源代码
因此问题长期存在,影响了所有基于V8引擎的环境。
我能够确认Chrome v27仍然受此问题影响且运行V8 v 3.16,并且可以确认Chrome v34与V8 v3.24.35.33不再受影响。因此,在这两者之间,V8的修复成为主流。
@cookiemonster的建议一个解决方案可能是使用更高版本的节点(来自他们不稳定的仓库),但我无法证实这一点。
我无法在node issues list中找到有关此问题的任何报告。
唯一的其他解决方案是测试此错误(上面给出的代码)并自己填充受影响的方法。我已经测试了这个解决方案并且它可以工作,这是我测试过的垫片。 (取自es5-shim project)
Array.prototype.forEach = function forEach(fun /*, thisp*/ ) {
'use strict';
var object = Object(this),
thisp = arguments[1],
i = -1,
length = object.length >>> 0;
// If no callback function or if callback is not a callable function
if (Object.prototype.toString.call(fun) !== '[object Function]') {
throw new TypeError(); // TODO message
}
while (++i < length) {
if (i in object) {
// Invoke the callback function with call, passing arguments:
// context, property value, property key, thisArg object
// context
fun.call(thisp, object[i], i, object);
}
}
};
该问题已被采纳: