JavaScript Object Prototypes

What is the Object Prototype in JavaScript?

Simply put, object prototypes are Javascript’s way of representing inheritance between objects. The prototype of an object (usually defined by the __proto__ property) is a reference to its parent object and it holds all the parent’s features that this object has inherited. This inheritance allows objects to access and utilize properties and methods defined in their prototype.

To demonstrate, let’s use the Object.create() function to create an object that inherits from another:

const car = {
	printMake () {
		console.log(this.make);
	}
}

// Create an object 'toyota' that inherits from the object 'car'
const toyota = Object.create(car);

// Let's set the 'make' property to 'Toyota'
toyota.make = 'Toyota';

toyota.printMake(); // Outputs: 'Toyota'

console.log(Object.getOwnPropertyNames(toyota)); // Outputs: [ 'make' ]
console.log(Object.getOwnPropertyNames(toyota.__proto__)); // Outputs: [ 'printMake' ]

In the example above, we used the car object as our parent and created the toyota object that inherits from it. After setting the make property, we call printMake() on toyota in line 13. Notice that printMake() was never defined on toyota, as shown in line 15, it’s not one of its properties. However, we were able to call it because toyota inherited it from car.

Since the car object is the parent, it’s referenced by toyota.__proto__ and printing its properties displays printMake as shown in line 16.

How the prototype chain works

The prototype of an object is itself an object, meaning it also has to have a prototype of its own. This forms what’s called the prototype chain, which ends with an object whose prototype is null.

When we try to access a property of an object, Javascript tries to find this property on the object itself. If it’s not there, it will check the properties of the object prototype. It will do this recursively down the prototype chain until the property is found or until it reaches the end of the chain.

So what if you create an object that doesn’t inherit from any other object? Will it have a null prototype? The answer is no. All objects in Javascript have a default prototype called Object.prototype. Here’s an example:

const obj = {};
console.log(Object.getOwnPropertyNames(obj.__proto__)); // Outputs: ["constructor", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "toLocaleString"]

We defined an empty object obj, we then accessed the properties of its prototype which turned out to be:

[
  "constructor",
  "__defineGetter__",
  "__defineSetter__",
  "hasOwnProperty",
  "__lookupGetter__",
  "__lookupSetter__",
  "isPrototypeOf",
  "propertyIsEnumerable",
  "toString",
  "valueOf",
  "__proto__",
  "toLocaleString"
]

These are the properties of the Object.prototype. And because of this, we can access any of these properties on obj and it will return its function definition, as opposed to returning undefined if we tried to access a property that doesn’t exist.

const obj = {};
console.log(Object.getOwnPropertyNames(obj.__proto__));

console.log(obj.toString) // Outputs: toString() { [native code] }
console.log(obj.valueOf) // Outputs: valueOf() { [native code] }
console.log(obj.propertyThatDoesntExist) // Outputs: undefined

Now, if we try to go one level deeper into the prototype chain and check the prototype of Object.prototype, we’ll get back null. Meaning that we have reached the end of the prototype chain:

const obj = {};
console.log(obj.__proto__.__proto__); // Outputs: null

Object Prototype vs Class in Javascript

Classes were introduced in ES6 to make Javascript look more similar to other popular object-oriented programming languages like Java or PHP.

// Define a class
class Car {
  constructor(make) { // constructor method
    this.make = make; // property
  }

  getMake() { // method
    return this.make;
  }
}

// Create an object of the Car class
let myCar = new Car("Toyota");

// Use the getMake method to get the make of the car
console.log(myCar.getMake()); // Outputs: Toyota

In the code above, we defined a class Car and we created myCar which is an instance of the class. Now myCar has the getMake() property on it; or has it?

Let’s check the properties of myCar:

console.log(Object.getOwnPropertyNames(myCar)); // Outputs: ['make']

myCar doesn’t have the getMake() method. Instead, the method exists in the prototype of myCar:

console.log(Object.getOwnPropertyNames(myCar.__proto__)); // Outputs: ['constructor', 'getMake']

This is because Javascript classes are not technically equivalent to classes in other programming languages. In fact, classes are primarily syntactical sugar over the existing Javascript prototype-based inheritance.
So under the hood, Javascript created an object called Car, and then created a new object called myCar using Car as its prototype. The code above is equivalent to the following code that uses the Object.create() function to create an object and set its prototype.

const Car = {
	getMake() {
		return this.make;
	}
}

const myCar = Object.create(Car);

myCar.make = 'Toyota';

console.log(myCar.getMake()); // Outputs: 'Toyota'

So if you’ve been asking yourself what’s the difference between object prototypes and classes in Javascript, there’s really no difference. You can use whatever syntax you like better. Just keep in mind that classes in Javascript are just a layer above prototypes and they behave in a similar fashion.

Similar Posts