Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point of "var t = Object(this)" in the official implementation of forEach?

Tags:

javascript

According to the MDC, the ECMA-262, 5th edition gives the implementation of forEach as:

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
      fun.call(thisp, t[i], i, t);
    }
  };
}

Can anyone tell me what the line "var t = Object(this)" is doing? How does Object(this) differ from plain this? And what work is that difference doing here?

like image 434
zjmiller Avatar asked Jun 27 '11 20:06

zjmiller


1 Answers

The Mozilla implementations just try to emulate exactly the steps that are described in the specification, Object(this); emulates the first step, calling the ToObject internal method:

From Array.prototype.forEach 15.4.4.18:

....

When the forEach method is called with one or two arguments, the following steps are taken:

  1. Let O be the result of calling ToObject passing the this value as the argument.

  2. Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".

  3. Let len be ToUint32(lenValue).

....

Calling the Object constructor as a function behind the scenes it performs type conversion, internally as described in 15.2.1.1 the ToObject method is called.

There are more things like this if you look carefully, for example, the line:

var len = t.length >>> 0;

They are emulating a call to the ToUint32 internal method, as described in the step 3, using the unsigned right shift operator (>>>).

Edit: The previous lines answer why the Mozilla implementation does it in this way.

You might wonder why the ECMAScript spec. needs to call ToObject, check back the Step 2, and it will start to seem obvious:

  1. Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".

The spec. needs to ensure that the this value used when the function is called is an object, because primitive values don't have any internal methods, an as you can see on the step 2, the [[Get]](P) internal method is needed, to get the value of the length property.

This is done because for strict functions (and also for built-in functions), you can set primitive values as the function's this value, e.g.:

(function () {"use strict"; return typeof this; }).call(5); // "number"

While for non-strict functions, the this value is always converted to Object:

(function () { return typeof this; }).call(5); // "object"
like image 115
Christian C. Salvadó Avatar answered Oct 15 '22 03:10

Christian C. Salvadó