Object.setPrototypeOf() Method JavaScript

There are two camps in JavaScript, one who uses function constructors to create objects and one who directly uses object literals. In JavaScript, function constructors can be extended by using the Object.create() method. This method lets you set prototype of one object to another object.

Constructor2.prototype = Object.create(Constructor1.prototype);

Extending Object Literals

Object literals don’t have prototype property. So, if you want to inherit properties of one literal to another, you can do it several ways. Prior to ES2015, you had to write your own extend method that would copy methods from one object to another. ES2015 introduced few new methods that makes this process easier. The setPrototypeOf() method is one of such methods.

Syntax

Object.setPrototypeOf(targetObj, sourceObj);

Here, targetObj is what you are setting prototype to from sourceObj. This method essentially sets a reference to sourceObj’s methods to targetObj’s __proto__. To understand the utility of this, let’s take two objects, toyota and camry. toyota has a drive() method. Setting the camry’s prototype to toyota makes toyota’s drive() method automatically available to camry. This is done by setting its reference in camry’s __proto__ property.


let toyota = {
  drive() {
    return 'driving toyota';
  }
}

let camry = {
  wifi() {
    return 'using wifi';
  }
}

// Set toyota's __proto__ to camry's  __proto__'s  __proto__
Object.setPrototypeOf(camry, toyota);

console.dir(camry); //prints the camry object
console.log(camry.wifi()); // using wifi
console.log(camry.drive()); // driving toyota

Object.setPrototypeOf()

If you inspect the camry object, you can view the __proto__ property and the reference to the drive() method of toyota. Since the setPrototypeOf() method sets a reference, any changes to toyota’s properties is automatically accessible to camry.

let toyota = {
  drive() {
    return 'driving toyota';
  }
};

let camry = {
  wifi() {
    return 'camry';
  }
};

// Set toyota's __proto__ to camry's  __proto__'s  __proto__
Object.setPrototypeOf(camry, toyota);

// Add a new Method to toyota object
toyota.newMethod = function() {
  return 'new method from toyota';
};

console.log(camry.newMethod()); // Prints 'new method from toyota' 



If you have a method with the same name in both the targetObject and the SourceObject, the method in the targetObject would have higher precedence. This is because javaScript first looks for object’s own method before looking into it’s prototype.

let toyota = {
  drive() {
    return 'driving toyota';
  }
}

let camry = {
  drive() {
   return 'driving camry';
  }
}

Object.setPrototypeOf(camry, toyota);
console.dir(camry.drive()); // logs "driving camry"

Super keyword

You can call the method of the sourceObject from the targetObject’s method by using the super keyword.

let toyota = {
  drive() {
    return 'driving toyota';
  }
}

let camry = {
  drive() {
   return `${super.drive()} camry`;
  }
}

Object.setPrototypeOf(camry, toyota);
console.dir(camry.drive()); // logs "driving toyota camry"

Avoid setting __proto__ manually

Prior to ES2015, Object.prototype.__proto__ was used to set the prototype of object literals. You can still use it as shown in the below example. However, it’s not recommended.

let toyota = {
  print() {
    return 'toyota';
  }
}

let camry = {
  printMe() {
    return 'camry';
  }
}

camry.__proto__ = toyota;

console.dir(camry.print());

Object.create method JavaScript

In JavaScript, Prototype inheritance is much easier than you would have imagined. Simply understand the fundamentals, like we always do!

Inheritance in JavaScript is prototype-based. Every constructor has a property called prototype. For more information about the basics of prototypes, click here.

Master constructor object ‘Object’

Object is the master constructor in JavaScript. Don’t forget to take a note of the capitalization of letter ‘O’ in Object. It’s a
function constructor. Directly or indirectly, every object is created by using Object (master object). Since, it is available in the global space, you can access it directly. If you console.dir(Object), you can view all methods that are available to Object. One of the methods is create(). It enables prototypal inheritance in JavaScript.

console.dir(Object);

Object.create Method

Syntax

Object.create(prototypeObject, propertiesObject);

The Object.create method takes two arguments. First argument must be either an object or null. The second argument is optional and used to set properties. These properties are set in object’s prototype.

Creating Objects

const myObject = Object.create(Object.prototype);
console.dir(myObject);

In the above example, the myObject object is created by using Object’s prototype. This means myObject’s creator is Object.prototype. If you inspect myObject, you can view the following:
Inspecting Object
myObject does not contain anything. However, its __proto__ property is a reference to the Object’s prototype. Hence, you can call methods on myObject that are available in Object’s prototype. If you create an object literal by using const myLiteral = {};, it possesses the same __proto__ because internally every object’s __proto__ is set to Object.prototype.To create an object without setting its __proto__ reference to Object.prototype, pass null as an argument. To verify this, inspect the object. As shown in the image below, it does not contain __proto__ property.

const myObject = Object.create(null);
console.dir(myObject);

Object.create(null)

The Object.create() method also creates objects from constructors. It is similar to using the new keyword. The only difference is that by using the new keyword, you can run the constructor. Hence, it will set the initial properties in the constructor. Whereas, the Object.create() method doesn’t run the constructor and hence the initial properties are not set.

const Car = function(color) {
  this.color = color;
};

let car1 = new Car('red');
let car2 = Object.create(Car.prototype);

console.dir(car1);
console.dir(car2);

New vs Object.create

Extending a Constructor

The main use of the Object.create() method is to extend the constructor. This means that you can inherit methods from a constructor’s prototype properties to other constructors. To extend a constructor, set a prototype reference of one object to another by using the Object.create() method.
Note: Only the constructor’s prototype is inherited and not the constructor.

const Car = function(color) {
  this.color = color;
};

Car.prototype.getColor = function() {
  return this.color;
}

const ToyCar = function() {};

ToyCar.prototype = Object.create(Car.prototype);

const legoCar = new ToyCar();

console.log(legoCar);

Object.create



Verifying Prototype

In the above example, ToyCar’s __proto__ is set to Car and Car’s __proto__ is set to Object. The isPrototypeOf method verifies if legoCar, which is originally created by using the ToyCar constructor, is a prototype of ToyCar, Car and Object. The instanceof operator also performs the similar task.

const Car = function() {};
const ToyCar = function() {};

ToyCar.prototype = Object.create(Car.prototype);

const legoCar = new ToyCar();

// Using the isPrototypeOf method
console.log(ToyCar.prototype.isPrototypeOf(legoCar)); //true
console.log(Car.prototype.isPrototypeOf(legoCar)); //true
console.log(Object.prototype.isPrototypeOf(legoCar)); //true

// Using the instanceof operator
console.log(legoCar instanceof ToyCar); //true
console.log(legoCar instanceof Car); //true
console.log(legoCar instanceof Object); //true

Conclusion

In the classical inheritance, you can create a subClass from a superClass. The subClass inherits all methods of the superClass. In JavaScript, a subConstructor inherits all methods from a superConstructor by using the Object.create method. Contrary to the classical inheritance, where methods of superClass are copied to subClass, JavaScript uses a prototype reference to access methods from the superConstructor.