如果我在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",length: 3}
var y = [1,3]; y.forEach(function (element) { 'use strict'; console.log(this); },'hej');
我得到一个输出
hej hej hej
这些是根据ECMA5规范sec-function.prototype.call所预期的结果.
The thisArg value is passed without modification as the this value. This is a change from Edition 3,where an undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value. Even though the thisArg is passed without modification,non-strict mode functions still perform these transfromations upon entry to the function.
If a thisArg parameter is provided,it will be used as the this value for each invocation of callbackfn. If it is not provided,undefined is used instead.
和相关的伪代码
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','2': 'j' }
任何人都可以确认这是否与我的节点环境有关,或者这是节点的问题吗?
更新:只是为了确认,在这两种情况下,这个返回对象的节点类型.
解决方法
错误报告可以在2012年8月5日发布的issue 2273中找到.
A strict mode function should receive a non-coerced ‘this’ value. That is,‘this’ can be undefined/null instead of the global object,and primitive values instead of Boxed values.
It does not matter whether the caller function is in strict mode or not. However,built-in functions such as ‘Array.prototype.forEach’ incorrectly do the coercion even though the function to be called is in strict mode.
Test case:
(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的建议解决方案可能是使用更高版本的节点(从他们的不稳定的repo),但我无法确认.
我在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); } } };
这个问题已经解决了: