Creating an instance of object using "new" operator works, but using Object.create() does not produce the same results

Viewed 62

A bit of a JavaScript newbie here. I have the following 2 JavaScript code snippets here which does not do what I am expecting. The examples create an instance of the object "Person" in Example #1 using the "new" operator, and creates a prototype of "Person" in Example #2 using the ES5 Object.create() property.

let Person = function(name, age, city) {
    this.name = name;
    this.age = age; 
    this.city = city
}

// Using 'new' operator (working)
let person1 = new Person("Jack Rabit", 40, "Seattle");
Object.values(person1); // Shows "Jack Rabit", 40, "Seattle"

But, doing the following using the Object.create() property...does not show the first value of the Property (in this case "name"):

let person2 = Object.create(Person);
person2.name = "Will"; 
person2.age=41; 
person2.city="San Jose";

Object.values(person2); // Shows 41, "San Jose" (Does NOT show the value of the "name" property)

What is that I am missing?

4 Answers

So usually when I use Object.create() I pass an object to be used at the prototype. You are currently passing a function as an argument. This way works

const Person = function(name, age, city) {
    this.name = name;
    this.age = age; 
    this.city = city
}

const person2 = Object.create(new Person());
person2.name = "Will"; 
person2.age=41; 
person2.city="San Jose";

Object.values(person2);

It probably has something to do with the fact that functions have their own name property for the function itself? But I'm not too sure

Edited:

Confirmed it is just because of the name property, changed name to title to avoid confusion:


const Person = function(title, age, city) {
    this.title = title;
    this.age = age; 
    this.city = city
}

const person2 = Object.create(Person);
person2.title = "Will"; 
person2.age=41; 
person2.city="San Jose";

Object.values(person2);
// ["Will", 41, "San Jose"]

Object.create creates a new object with the given object as its [[prototype]].

You are trying to inherit the properties wrongly here. You are creating the person2 object with the constructor function Person as its prototype. All functions have a non-enumerable and non-writable property called name. You can see that by

Object.getOwnPropertyDescriptor(Person, "name")

The line person2.name = "Will"; is effectively trying to overwrite this property and does nothing. Also person2 has effectively become a function.

Here the correct usage would be

let person2 = Object.create(new Person()); 

Object.create needs an object to create another object. So use the Person function to return an object. It should look like this:

 let Person = function(name, age, city) {
  return {
    name,
    age,
    city
  };
}

// Using 'new' operator (working)
let person1 = new Person("Jack Rabit", 40, "Seattle");

let person2 = Object.create(Person());
person2.name = "Will"; 
person2.age=41; 
person2.city="San Jose";

Object.create needs an object to create another object, as a result since Person while being a function(a function constructor to be exact) is also an object in javaScript. Therefore Object.create will not complain, but what is happening under the hood when its done this way:

let person2 = Object.create(Person);

person2 ends up being assigned some of the properties of a function named 'Person' (which in itself is not a function, it can t be called) this can be seen here:

// person2.name = 'Person'

// person2() Uncaught TypeError: person2 is not a function at <anonymous>:1:1

As one of the inherited properties of a Function, its name is read-only, therefore person2.name = 'some name' will have no effect. Function.name MDN docs

The new operator will call the constructor which will return an object while inheriting the prototype of the constructor function

Related