4

I was going through the Array'a find polyfill implementation on MDN:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find?v=control#Polyfill

Copy pasting it below:

  // https://tc39.github.io/ecma262/#sec-array.prototype.find
  if (!Array.prototype.find) {
    Object.defineProperty(Array.prototype, 'find', {
      value: function(predicate) {
       // 1. Let O be ? ToObject(this value).
        if (this == null) {
          throw new TypeError('"this" is null or not defined');
        }

        var o = Object(this);

        // 2. Let len be ? ToLength(? Get(O, "length")).
        var len = o.length >>> 0;

        // 3. If IsCallable(predicate) is false, throw a TypeError exception.
        if (typeof predicate !== 'function') {
          throw new TypeError('predicate must be a function');
        }

        // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
        var thisArg = arguments[1];

        // 5. Let k be 0.
        var k = 0;

        // 6. Repeat, while k < len
        while (k < len) {
          // a. Let Pk be ! ToString(k).
          // b. Let kValue be ? Get(O, Pk).
          // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
          // d. If testResult is true, return kValue.
          var kValue = o[k];
          if (predicate.call(thisArg, kValue, k, o)) {
            return kValue;
          }
          // e. Increase k by 1.
          k++;
        }

        // 7. Return undefined.
        return undefined;
      }
    });
  }

Why is it that we need to do var o = Object(this);?

What does Object(this) achieve?

Thanks for any discussion.

6
  • The point of doing that is to deal with the cases when this is a primitive. To convert it into an object. Commented May 19, 2017 at 22:19
  • @Will, null and undefined values are already dealt with here: if (this == null) throw .... The o = Object(this) part is only interesting when this is a string Commented May 19, 2017 at 22:22
  • I was thinking along the lines of this being a primitive and Object(this) converting it into an Object too, but could this actually be a primitive? How would a primitive call the polyfill? Even if it could, wouldn't it have a length of undefined and the rest of the code still function? 1.length throws a Syntax error, but var num = 1; num.length does not throw an error. Commented May 19, 2017 at 22:44
  • @Thomas, agreed. I was making a more general comment. The question does not specify whether it pertains only to usage in the context of this particular code or more generally. Commented May 22, 2017 at 13:51

2 Answers 2

5

In strict mode, a primitive this will not be coerced to an object.

Therefore, explicit coercion to an object using Object(this) is necessary.

Here is a more detailed example:

const array = Array.prototype;

Object.defineProperty(array, 'foo1', { value() { 
  return this.length >>> 0;  }});

Object.defineProperty(array, 'foo2', { value() { 
  "use strict"; 
  return this.length >>> 0; }});

console.log(Array.prototype.foo1.call(undefined));
console.log(Array.prototype.foo2.call(undefined));

The first example runs successfully with a result of 0, because the argument undefined is coerced to an object in non-strict mode. The second example fails, because undefined is not coerced in non-strict mode, and thus this.length errors out.

From MDN:

the value passed as this to a function in strict mode is not forced into being an object (a.k.a. "boxed")

However, in this case, there is already an explicit check for null or undefined:

if (this == null) {
  throw new TypeError('"this" is null or not defined');
}

so I am tempted to say the explicit casting to an object is not necessary. It is probably used here out of an abundance of caution, or as boilerplate.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for the explanation.
4

This is a fascinating question... Thanks for your post!

To be honest, I am a bit surprised by Object(this) because JavaScript seems to coerce anything to object (using wrappers) in situations where this could potentially be a primitive value.

If we try to change this with Function.prototype.bind(), JavaScript always returns an object (a function is an object):

var foo = function () {
  console.log(this, typeof this);
}.bind('foo');

var bar = function () {
  console.log(this, typeof this);
}.bind(1337);

var baz = function () {
  console.log(this, typeof this);
}.bind(false);

var qux = function () {
  console.log(this, typeof this);
}.bind(NaN);

var quux = function () {
  console.log(this, typeof this);
}.bind(undefined);

var corge = function () {
  console.log(this, typeof this);
}.bind(null);

var grault = function () {
  console.log(this, typeof this);
}.bind([]);

var garply = function () {
  console.log(this, typeof this);
}.bind({});

var waldo = function () {
  console.log(this, typeof this);
}.bind(/regex/);

var fred = function () {
  console.log(this, typeof this);
}.bind(function () {});

foo(); // String { 0: "f", 1: "o", 2: "o" } object
bar(); // Number { 1337 } object
baz(); // Boolean { false } object
qux(); // Number { NaN } object
quux(); // Window object
corge(); // Window object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function   

If we try to change this with Function.prototype.call() or Function.prototype.apply(), once again, JavaScript always returns an object:

Array.prototype.foo = function () {
  console.log(this, typeof this);
};

['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // String { 0: "b", 1: "a", 2: "r"} object
Array.prototype.foo.call(42); // Number { 42 } object
Array.prototype.foo.call(true); // Boolean { true } object
Array.prototype.foo.call(NaN); // Number { NaN } object
Array.prototype.foo.call(undefined); // Window object
Array.prototype.foo.call(null); // Window object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function

In JavaScript, we know that native objects may be useful for type conversion when they are not used as constructors but as regular functions. Number, String and Boolean are quite convenient:

var num = 1337,
    str = '',
    bool = true;
    
console.log(Number(str), typeof Number(str));
console.log(Number(bool), typeof Number(bool));

console.log(String(num), typeof String(num));
console.log(String(bool), typeof String(bool));

console.log(Boolean(num), typeof Boolean(num))
console.log(Boolean(str), typeof Boolean(str));

For the record, here is what we get with explicit conversions through Object():

console.log(typeof Object(false), Object(false) instanceof Boolean);
console.log(typeof Object('bar'), Object('bar') instanceof String);
console.log(typeof Object(42), Object(42) instanceof Number);
console.log(typeof Object(NaN), Object(NaN) instanceof Number);
console.log(typeof Object(undefined), Object(undefined) instanceof Object);
console.log(typeof Object(null), Object(null) instanceof Object);
console.log(typeof Object(['foo']), Object(['foo']) instanceof Array);
console.log(typeof Object({}), Object({}) instanceof Object);
console.log(typeof Object(/regex/), Object(/regex/) instanceof RegExp);
console.log(typeof Object(function () {}), Object(function () {}) instanceof Function);

Now it is obvious that Object(this) can be used to convert any primitive value for this and get a wrapper object instead. If this is already an object, it has no effect:

var obj1 = {baz: 'Baz'},
    obj2 = Object(obj1);

var arr1 = ['foo', 'bar'],
    arr2 = Object(arr1);
    
var reg1 = /regex/,
    reg2 = Object(reg1);
    
var fun1 = function () { return 'Hello!'; },
    fun2 = Object(fun1);
    
console.log(arr1 === arr2);
console.log(obj1 === obj2);
console.log(reg1 === reg2);
console.log(fun1 === fun2);

Moreover, Object is weird because it acts in the same way, whether it is called with new or not:

var foo = Object('foo'),
    bar = new Object('bar');
    
console.log(foo);
console.log(bar);

I may be wrong, but my conclusion is the following: given that this is always coerced to an object, Object(this) is not necessary. However, it indicates explicitly what happens implicitly to avoid ambiguity and improve code comprehension.

What do you think?


EDIT

torazaburo is right: strict mode is the key! When functions are in strict mode, primitive values for this are not coerced! This is probably the most reasonable explanation for explicit conversion with Object(this)...

Function.prototype.bind()

var foo = function () {
  'use strict';
  console.log(this, typeof this);
}.bind('foo');

var bar = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(1337);

var baz = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(false);

var qux = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(NaN);

var quux = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(undefined);

var corge = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(null);

var grault = function () {
  'use strict';
  console.log(this, typeof this);
}.bind([]);

var garply = function () {
  'use strict';
  console.log(this, typeof this);
}.bind({});

var waldo = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(/regex/);

var fred = function () {
  'use strict';
  console.log(this, typeof this);
}.bind(function () {});

foo(); // foo string
bar(); // 1337 number
baz(); // false boolean
qux(); // NaN number
quux(); // undefined undefined
corge(); // null object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function

Function.prototype.call()

Array.prototype.foo = function () {
  'use strict';
  console.log(this, typeof this);
};

['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // bar string
Array.prototype.foo.call(42); // 42 number
Array.prototype.foo.call(true); // true boolean
Array.prototype.foo.call(NaN); // NaN number
Array.prototype.foo.call(undefined); // undefined undefined
Array.prototype.foo.call(null); // null object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function

2 Comments

Thanks for such detailed answer. I myself wasn't sure why on earth did they use Object(this), and puzzled the hell out of me. The strict mode seems like the reason. I will accept this answer just because your explanation is step by step like a tutorial, explaining why the puzzle is a puzzle, very detailed and easy to understand for future readers.
Note to future readers, please read @torazaburo's answer in addition to this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.