使用'thisArg'和'use strict'的Nodejs方法; 问题

我在Fedora 19上安装了v0.10.28节点和V8 v3.14.5.9。我遇到的问题是具有thisArg可选参数的方法,比如Array.prototype.forEach

如果我在Chromium v​​33或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被replace为全局对象和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

在V8 v3.14.5.9(及更早的版本)中安装了节点v0.10.28(最新稳定版本),但问题并不在于节点本身,而是V8,它有一个缺陷。

错误报告可以在2012年8月5日发布的第2273期中find。

一个严格的模式函数应该得到一个非强制的“this”值。 也就是说,'this'可以是undefined / null而不是全局对象,原始值而不是盒装值。

来电function是否处于严格模式并不重要。 但是,即使要调用的函数处于严格模式,诸如“Array.prototype.forEach”之类的内置函数也会错误地进行强制转换。

testing用例:

 (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日提交给版本r14149中的V8源代码

所以这个问题长期存在,影响了所有基于V8引擎的环境。

我可以确认Chrome v27仍然受到此问题的影响,并且正在运行V8 v 3.16,并且可以确认Chrome v34与V8 v3.24.35.33不再受影响。 所以在这两个之间的V8修复成为主stream。

@cookiemonster的build议一个解决scheme可能是使用更高版本的节点(从他们不稳定的回购),但我无法证实这一点。

在节点问题列表中,我一直无法find这个问题的任何报告。

唯一的解决方法是testing这个bug(上面给出的代码)并自己填充受影响的方法。 我已经testing了这个解决scheme,它的工作原理,这是我testing的垫片。 (取自es5-shim项目 )

 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); } } }; 

这个问题已经被采纳:

  1. idiomatic.js
  2. ES5,垫片
  3. 的NodeJS