Radu Szasz
Radu Szasz

Reputation: 1021

JavaScript: How is Object implemented such that new Object({}) and Object({}) are the same

In JavaScript, I can write:

x = new Object({ a: 3 })

and I will have x = { a: 3 }

Similarly, I can write

x = Object({ a: 3 })

and I will have x = { a: 3 } again.

My question is: How is Object implemented to satisfy both these ways of calling it? In the first scenario, it will receive a fresh this, while in the second it will receive the global object.

My best guess is something like:

var Object = function(obj) {
    var global = (function() { return this; })();
    if (global == this) { // I am called as a regular function
        // Create a copy of obj, potentially like this
        return { ...obj };
    } else { // I am called via new
        // Copy all fields of obj onto this
        // not sure what the best way to do this is.
    }
}

Upvotes: 4

Views: 74

Answers (3)

AlexScr
AlexScr

Reputation: 452

It's simple as that

function Object(obj) {
  return obj;
}

When you call it as function it inherits its parent's scope that is window. Buy when you initialize it as a class, the function itself is the constructor that has its own scope this.

And it's not creating a new instance with copied properties as you can see in this example:

var a = {a : 3};
var b = new Object(a);
var c = Object(a);

console.log(a === b);
console.log(a === c);

As @user2357112 specified that it's not that simple here is a more close to Object functionality:

function Object(value) {
  if (typeof value === 'number') {
    return new Number(value);
  }
  
  if (typeof value === 'string') {
    return new String(value);
  }
  
  if (value === null || value === undefined) {
    return {};
  } 
  
  return value
}

var a = new Object(undefined);

console.log(new Object(1));
console.log(new Object('sad'));
console.log(new Object([]));
console.log(new Object({}));
console.log(new Object(null));
console.log(new Object());

Upvotes: -1

T.J. Crowder
T.J. Crowder

Reputation: 1074989

The answer is in the specificaton:

When Object function is called with optional argument value, the following steps are taken:

  1. If NewTarget is neither undefined nor the active function, then
    • Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
  2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
  3. Return ! ToObject(value).

Step #1 is about what the code should do when the call is happening as part of creating something that inherits from Object, so we can ignore that step for your question.

Step #2 doesn't apply because you're passing in value and it's neither null nor undefined.

So Step #3 is what happens: It uses the ToObject operation to do type conversion to turn value into an object. Since value is already an object, that's a no-op, and the result is the same object you passed in. The new Object part of new Object({a: 1}) is completely unnecessary.

In the first scenario, it will receive a fresh this, while in the second it will receive the global object.

As you can see from the spec steps above, Object doesn't use this at all.

Upvotes: 4

Oleksandr Poshtaruk
Oleksandr Poshtaruk

Reputation: 2146

I think it is something like

function Object(obj) {
  If (this instanceof Object) {
       return Object.assign(this, ...obj)
     }
  return new Object(obj);
 }

Upvotes: -1

Related Questions