Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs methods with 'thisArg' and 'use strict'; issue

I have node v0.10.28 installed along with V8 v3.14.5.9 on Fedora 19. The issue I am having is with methods that have a thisArg optional argument, like Array.prototype.forEach.

If I execute the following code on Chromium v33 or Firefox v28 - jsFiddle

var y = [1, 2, 3];

y.forEach(function (element) {
    console.log(this);
}, 'hej');

I get an output of

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}

And then the same code but in strict mode - jsFiddle

var y = [1, 2, 3];

y.forEach(function (element) {
    'use strict';
    console.log(this);
}, 'hej');

I get an output

hej
hej
hej

These are the results that I would expect as per the ECMA5 specification 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.

and for example 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.

and relevant pseudo code

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.

On node, however, both the above snippets return

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

Can anyone confirm whether this is an issue with my node environment, or if this is a problem with node?

Update: just to confirm, in both cases on node typeof this returns object.

like image 950
Xotic750 Avatar asked May 06 '14 01:05

Xotic750


People also ask

Should you use strict in NodeJS?

Nodejs is server-side javascript, so many coding practices are similar in both. So using strict mode is common. It ensures that you are not violating certain coding conventions like undeclared variables x=14; , use of specific variable names arguments,eval which are names of few global variables and functions.

What are the advantages and disadvantages of using use strict?

what are the advantages and disadvantages to using it? If you put "use strict"; at the top of your code (or function), then the JS is evaluated in strict mode. Strict mode throws more errors and disables some features in an effort to make your code more robust, readable, and accurate.

Should I use strict mode js?

First, all of your code absolutely should be run in strict mode. Core modern javascript functionality is changed (see . call() and apply()) or disfigured (silent Errors) by executing code outside of strict mode.


1 Answers

The problem does exist with node v0.10.28 (latest stable) installed along with V8 v3.14.5.9 (and earlier versions), but the problem is not node itself but with V8, which has a bug.

The bug report can be found in issue 2273 posted on Aug 5, 2012.

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

The bug fix was committed to the V8 source code in revision r14149 on Apr 5, 2013

So the problem was long standing and affected all environments that were based on the V8 engine.

I was able to confirm that Chrome v27 was still affected with this issue and it was running V8 v 3.16, and can confirm that Chrome v34 with V8 v3.24.35.33 is no longer affected. So somewhere between these 2 the fix for V8 went mainstream.

A suggestion by @cookiemonster A solution may be to use a later version of node (from their unstable repo) but I can not confirm this.

I have not been able to find any report of this issue in the node issues list.

The only other solution is to test for this bug (code given above) and to shim the affected methods yourself. I have tested this solution and it works, here is the shim that I tested with. (taken from the 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);
        }
    }
};

The issue has been taken up with:

  1. idiomatic.js
  2. es5-shim
  3. nodejs
like image 73
Xotic750 Avatar answered Nov 15 '22 17:11

Xotic750