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

旧时模样 提交于 2019-12-02 17:18:26

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"

The probable reason is s9.9 of ECMA-262, about the abstract ToObject operation (as mentioned by @CMS).

When called on null or an undefined value it forces the throwing of a TypeError, but those are already trapped by the previous lines.

However if you were to call:

Array.prototype.forEach.call("123", func() { ... } )

this would fail if it weren't for the type coercion. In particular you can't call index in this if this is a string, but you can call it on the result of ToObject.

This text from 15.4.4.18 is probably relevant:

The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the forEach function can be applied successfully to a host object is implementation-dependent.

Jeremy Sher

I write var t = this; all the time. I find that the scope of this is sometimes browser-dependent; in any case it's not always clear what a browser is going to do with the keyword this as scope changes, especially in method closures. I like to dumb down my JS code to a kindergarten level to leave minimal room for individual browsers to do wonky things.

To ensure that I'm always dealing with the this I want to be dealing with when passing this to a method or something, I always write var t = this; as the first line of my method. Then, t is a variable and obeys predictable variable scope rules, and its pointer is assigned at assignment time to the object denoted by this at that time. This way I don't have to worry about a method, other object, or noncompliant browser reinterpreting what this refers to in scope.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!