bits bits - 1 year ago 32
Javascript Question

What is the purpose of doing `Object(this)`?

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.

Answer Source

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
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download