2

I am trying to distinguish certain differences in the way of creating new objects. Basically, you can create a new object via object literal ( const obj = {}; ), as a member of a certain class ( const obj = new MyObjClass; ), as a result of a constructor function or by calling Object.create().

Every entity in javascript is an object, even functions, thus everything has .__proto__ property, but only functions may have (or may not have) .prototype property. Child's .__proto__ property is equal to it's parent's .prototype property. Inside .prototype property of such functions you may find .constructor() method, which is invoked when you are calling such functions with "new" keyword.

This works for classes and constructor functions: you call new YourFunction(), then in return you get a new object with it's __proto__ pointing to parent's .prototype, also .prototype.constructor() is invoked, which job is to set properties and methods of the final object.

But if you use Object.create(), instead of "new" keyword, is it possible to completely recreate the behavior of "new" keyword?

Here I've tried to recreate it, it seems that it works fine, but when you console.dir() every final object, you see rather different results. So..

What are the core differences between those ways of creating new objects? Is there something below the surface, or it is just the matter of personal preferences?

const objStorage = {}; // just a storage variable so it is easy to pass it to console.dir()

const obj0 = {  // Declaring an object literal, so that we can pass it to Object.create()
  state: "inside Object.create()",
  showState() { console.log("State: " + this.state) }
}

function Obj1() {  // Making constructor function
  this.state = "inside constructor Function()";
  this.showState = function () { console.log("State: " + this.state) }
}

class Obj2 {  // Making class declaration
  constructor() {
    this.state = "inside Class";
    this.showState = function () { console.log("State: " + this.state) }
  }
}

const obj3 = function(){  // Trying to recreate class functionality, so that it can be used both ways
  let self = {};
  self.state = "inside self-made constructor";
  self.showState = function () { console.log("State: " + this.state) }
  return self
};
obj3.prototype = {};
obj3.prototype.constructor = obj3;

objStorage.a = Object.create(obj0); 
objStorage.b = new Obj1; 
objStorage.c = new Obj2; 
objStorage.d = new obj3.prototype.constructor; 
objStorage.e = Object.create(obj3()); 

objStorage.a.showState(); // State: inside Object.create()
objStorage.b.showState(); // State: inside constructor Function()
objStorage.c.showState(); // State: inside Class
objStorage.d.showState(); // State: inside self-made constructor
objStorage.e.showState(); // State: inside self-made constructor
IsleBeeGun
  • 33
  • 6
  • You're talking of "child" and "parent", but it really should be "instance" and "class". – Bergi Jun 27 '20 at 17:04

1 Answers1

3

The key difference between Object.create() and the new operator is that, while they both create an object with a prototype chain derived from the prototype object passed, only the new operator invokes the constructor with the newly created object applied as this, while Object.create() does not.

Here's a couple demonstrations of the effects of this difference:

const a = new Array();
const b = Object.create(Array.prototype);

console.log(Array.isArray(a));
console.log(Array.isArray(b));

const c = new Map();
const d = Object.create(Map.prototype);

console.log(c.set('foo', 'bar'));
console.log(d.set('foo', 'bar'));

In most cases, there should be no reason to directly use Object.create(). The constructor often initializes internal members that are necessary for the object to work as expected.

To answer your other question, no, new cannot be completely recreated using Object.create(), but it can be by using Reflect.construct() instead.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • Patrick, thank you a lot! I'll try to dig in `Reflect.construct()` , but overall it now seems that Object.create() is designed for some other purposes.. **Object.create() does not invoke the constructor** - the main point, I guess – IsleBeeGun Jun 27 '20 at 16:59