javascript - 带有 'thisArg' 和 'use strict' 的 Nodejs 方法;问题

标签 javascript node.js strict

我在 Fedora 19 上安装了 Node 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 所期望的结果.

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.

例如 sec-array.prototype.foreach

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.

然而,在 Node 上,上述两个片段都返回

{ '0': 'h', '1': 'e', '2': 'j' }
{ '0': 'h', '1': 'e', '2': 'j' }
{ '0': 'h', '1': 'e', '2': 'j' }

谁能确认这是我的 Node 环境的问题,还是 Node 的问题?

更新:只是为了确认,在 Node typeof this 上的两种情况下都返回 object

最佳答案

与 V8 v3.14.5.9(及更早版本)一起安装的 node v0.10.28(最新稳定版)确实存在问题,但问题不在于 node 本身,而在于 V8,它有一个错误。

可以在 issue 2273 中找到错误报告。发布于 2012 年 8 月 5 日。

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

错误修复已提交到 revision r14149 中的 V8 源代码2013 年 4 月 5 日

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

我能够确认 Chrome v27 仍然受到此问题的影响,并且它正在运行 V8 v 3.16,并且可以确认带有 V8 v3.24.35.33 的 Chrome v34 不再受到影响。所以在这两者之间的某个地方,V8 的修复成为了主流。

@cookiemonster 的建议一个解决方案可能是使用更高版本的 Node (来自他们的不稳定 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);
        }
    }
};

该问题已被处理:

  1. idiomatic.js
  2. es5-shim
  3. nodejs

关于javascript - 带有 'thisArg' 和 'use strict' 的 Nodejs 方法;问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23484732/

相关文章:

database - 什么是严格的时间表?

MySQL 在 where 子句中使用带有子索引的严格模式

javascript - ng-无效关注输入或选择元素

javascript - 如何将参数传递给 Javascript 模块?

node.js - 使用 Node.js 进行条件二进制解包

javascript - 在严格模式下使用delete删除对象条目

javascript - 如何使用按钮重置 <select> 菜单?

javascript - javascript中的递归函数或循环?

javascript - 如何将 GET 请求从 app.js 中的根目录重新路由到 Express.js 中 Controller 文件夹中的路由?

node.js - 如何在自定义 through2 流中内部链接流