Skip to content

Instantly share code, notes, and snippets.

@amerrika
Last active April 7, 2024 08:56
Show Gist options
  • Save amerrika/6e94e272ab8b4eed09cab51024aa84e0 to your computer and use it in GitHub Desktop.
Save amerrika/6e94e272ab8b4eed09cab51024aa84e0 to your computer and use it in GitHub Desktop.
JavaScript Prototype

Prototypes

Prototypes are the mechanism by which JavaScript objects inherit methods and properties from one another. Prototypes are important part of JavaScript and therefore it's important to understand the basics of this concept.

The goal of this article is to show how prototype object of constructor functions is used to pass methods and properties to its instances.

Prototype as a Property of Functions

In JavaScript, functions are objects. They are instances of the Function() constructor and this way every created function inherit certain methods and properties. One such inherited property is prototype. Initial value of the prototype is an empty object. Arrow functions are an exception, they do not have the prototype object and cannot be used as a constructor.

Let's create a simple function and we'll see that by default it contains the prototype property

function myFunction(){
  return a + b
}
console.log(myFunction)
console.log(myFunction.prototype) // {}

Screenshot from 2024-04-02 16-03-56

Now, we can add methods and properties to this prototype object and they will not effect the function itself. They will only be used if the function is used as a constructor and this way its instances would inherit methods and properties from the prototype object.

Let's Work with a Constructor Function

Let's create a constructor function named Device() so that we can observe how this prototype object actually works.

function Device(name, color) {
  this.name = name;
  this.color = color;
}

Now, we create someDevice instance using new operator:

const someDevice = new Device("monitor", "silver")
console.log(someDevice)

Screenshot from 2024-04-02 16-16-00

As we can see, our someDevice object has two properties, that is name and color. Let's say, we want every object created with Device() constructor to have a priceRequired property with boolean value of true. For that, we can use the prototype object of the constructor.

Device.prototype.priceRequired = true
console.log(Device.prototype)

Screenshot from 2024-04-02 16-19-02

Now we can see that prototype object of the Device() constructor is no longer empty as it contains the priceRequired property. Every object that was created and that will be created using the Device() constructor will detect these changes. Our someDevice object now has access to this new property.

console.log(someDevice.priceRequired) // true

Own Properties vs Inherited Properties

We can recognize that someDevice object has two own or direct properties. Those properties are name and color. We can check that using the hasOwnProperty() method.

console.log(someDevice.hasOwnProperty("name")) // true
console.log(someDevice.hasOwnProperty("color")) // true

What will happen if we check the priceRequired property like we've done with name and color? We'll get false value because the priceRequired in this case is inherited property.

console.log(someDevice.hasOwnProperty("priceRequired")) // false

We created priceRequired property inside the prototype object of the Device() constructor function. Therefore the priceRequired is direct property of the prototype object.

console.log(Device.prototype.hasOwnProperty("priceRequired")) // true

If we need access to a certain property, JavaScript will always first look up own properties of an object. Then, if JavaScript does not find it there, it will recognize the prototype object of its constructor and will search there for the property. If the property is not found it will return undefined.

Prototype Properties Are Not Cloned

The reason the priceRequired is not a direct property of someDevice is that in JavaScript objects are copied by reference and not by value. That means, the prototype object of a constructor function is not cloned into every instance but the instances have a 'link' to the prototype object. In practice this means that any modification in the prototype object will be recognized by the instances.

console.log(someDevice.priceRequired === someDevice.constructor.prototype.priceRequired); // true
console.log(someDevice.priceRequired === Device.prototype.priceRequired); // true
console.log(someDevice.constructor.prototype === Device.prototype); // true

Here we can see that there is only one copy of priceRequired property and only one copy of prototype object of Device() constructor function. That's why we get true for these comparisons.

Now, if we change the value of priceRequired to false, all instances, the already created ones and those that will be created will recognize this change.

Device.prototype.priceRequired = false;
console.log(someDevice.priceRequired) // false

"Internal" prototype property of objects

Every JavaScript object has an "internal" prototype property which points to the object from which it directly inherits. It's called [[prototype]] in Chrome and < prototype > in Firefox. Getter for this internal property is Object.getPrototypeOf(). We are going to inspect someDevice in the console.

console.log(someDevice)

Screenshot from 2024-04-03 18-16-38

We notice that < prototype > points directly to the prototype object of the Device() constructor function.

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment