JS prototypes and property values

Let’s continue the investigation of JavaScript prototypes we started last time by seeing what happens when we manipulate properties on prototypes in various ways.

Changing prototype properties through the constructor

You might be wondering what happens when you change a property you’ve defined on a prototype using the constructor’s prototype property. The answer is that any change you make to the prototype in this way is reflected in all instances made from that constructor.

function Person(name) {
  this.name = name;
}
Person.prototype.greeting = 'Hello. My name is';
Person.prototype.sayName = function() {
  console.log(this.greeting, this.name + '.');
};

var fuzz = new Person('Fuzz');
var athena = new Person('Athena');

Person.prototype.greeting = "Merhaba. Benim adim"

fuzz.sayName();   // Merhaba. Benim adim Fuzz.
athena.sayName(); // Merhaba. Benim adim Athena.

Changing prototype properties through an object

The next question then might be, does the same thing happen when you change a prototype’s property using an object? The answer is yes, it does.

function Person(name) {
  this.name = name;
}
Person.prototype.greeting = 'Hello. My name is';
Person.prototype.sayName = function() {
  console.log(this.greeting, this.name + '.');
};

var fuzz = new Person('Fuzz');
var athena = new Person('Athena');

fuzz.__proto__.greeting = "Merhaba. Benim adim"

fuzz.sayName();   // Merhaba. Benim adim Fuzz.
athena.sayName(); // Merhaba. Benim adim Athena.

Property shadowing

Finally, what if you make the change directly on the object itself?

function Person(name) {
  this.name = name;
}
Person.prototype.greeting = 'Hello. My name is';
Person.prototype.sayName = function() {
  console.log(this.greeting, this.name + '.');
};

var fuzz = new Person('Fuzz');
var athena = new Person('Athena');

fuzz.greeting = "Merhaba. Benim adim"

fuzz.sayName();   // Merhaba. Benim adim Fuzz.
athena.sayName(); // Hello. My name is Athena.

In this case, only the instance has been affected!

When you assign to an object’s property that’s actually in its __proto__, the JavaScript engine will make a new property on the object, and that will then shadow the property on its __proto__:

console.log ( fuzz.hasOwnProperty('greeting') );
console.log ( fuzz.greeting );  // Merhaba. Benim adim

console.log ( fuzz.__proto__.hasOwnProperty('greeting') );
console.log ( fuzz.__proto__.greeting );  // Hello. My name is

In theory this means that you could set all of an object’s properties using the constructor’s prototype and then update only what needs to be changed from that using the dot operator directly on instances.

function Person() {
}
Person.prototype.name = "unknown"
Person.prototype.greeting = 'Hello. My name is';
Person.prototype.sayName = function() {
  console.log(this.greeting, this.name + '.');
};

var displacedPerson = new Person();
var fuzz = new Person();
fuzz.name = "Fuzz";

displacedPerson.sayName();  // Hello. My name is unknown.
fuzz.sayName();  // Hello. My name is Fuzz.

This is a design pattern favored by some, but you’ll have to decide whether the potential memory savings are worth the additional coder burden of explicitly setting property values after instantiation.

Next up, we’ll talk about the prototype chain.

Leave a Reply

Your email address will not be published. Required fields are marked *