Javascript Object Oriented Design - Javascript Prototypes with Constructor








The shared nature of prototypes makes them ideal for defining methods once for all objects of a given type.

It's much more efficient to put the methods on the prototype and then use this to access the current instance.

Example

For example, consider the following new Book constructor:


function Book(name) { //  ww w .j a v a2  s. com
    this.name = name; 
} 

Book.prototype.writeLine = function() { 
    console.log(this.name); 
};

var book1 = new Book("Javascript"); 
var book2 = new Book("CSS"); 

console.log(book1.name);          // "Javascript" 
console.log(book2.name);          // "CSS" 

book1.writeLine();                  // outputs "Javascript" 
book2.writeLine();                  // outputs "CSS" 

The code above generates the following result.





Note

We can also store other types of data on the prototype, but be careful when using reference values because these values are shared across instances.


function Book(name) { // w  ww .j a  v a  2  s .  c  om
    this.name = name; 
} 

Book.prototype.writeLine = function() { 
    console.log(this.name); 
}; 
Book.prototype.favorites = []; 

var book1 = new Book("Javascript"); 
var book2 = new Book("CSS"); 

book1.favorites.push("A"); 
book2.favorites.push("B"); 

console.log(book1.favorites);     // "A,B" 
console.log(book2.favorites);     // "A,B" 

The code above generates the following result.





Note 2

The following code shows how to add more methods to prototype:


function Book(name) { /*  w  ww .ja  va 2  s .  c o m*/
    this.name = name; 
} 

Book.prototype = { 
   writeLine : function() { 
        console.log(this.name); 
    }, 

   toString : function() { 
        return "[Book " + this.name + "]"; 
    } 
}; 

The code above defines two methods on the prototype, writeLine() and toString().

There is one side effect to be aware of:


function Book(name) { //w ww.java 2s . c  o m
    this.name = name; 
} 

Book.prototype = { 
   writeLine : function() { 
        console.log(this.name); 
    }, 

   toString : function() { 
        return "[Book " + this.name + "]"; 
    } 
}; 

var book1 = new Book("Javascript"); 

console.log(book1 instanceof Book);         // true 
console.log(book1.constructor === Book);    // false 
console.log(book1.constructor === Object);    // true 

The code above generates the following result.

To avoid this, restore the constructor property to a proper value when overwriting the prototype:


function Book(name) { //from w  ww. j a  va  2s .com
    this.name = name; 
} 

Book.prototype = { 
    constructor : Book, 

    writeLine : function() { 
        console.log(this.name); 
    }, 

    toString : function() { 
        return "[Book " + this.name + "]"; 
    } 
}; 

var book1 = new Book("Javascript"); 
var book2 = new Book("CSS"); 

console.log(book1 instanceof Book);         // true 
console.log(book1.constructor === Book);    // true 
console.log(book1.constructor === Object);    // false 

console.log(book2 instanceof Book);         // true 
console.log(book2.constructor === Book);    // true 
console.log(book2.constructor === Object);    // false 

The code above generates the following result.

Changing Prototypes

Since all instances of a particular type reference a shared prototype, we can augment all of those objects.

The [[Prototype]] property contains a pointer to the prototype, and any changes to the prototype are available on any instance referencing it.

We can add new members to a prototype at any point and have those changes reflected on existing instances.


function Book(name) { /*from  w ww. ja  v a  2 s.  co m*/
   this.name = name; 
} 

Book.prototype = { 
   constructor : Book, 

   writeLine : function() { 
       console.log(this.name); 
   }, 

   toString : function() { 
       return "[Book " + this.name + "]"; 
   } 
}; 
var book1 = new Book("Javascript"); 
var book2 = new Book("CSS"); 

console.log("sayHi" in book1);        // false 
console.log("sayHi" in book2);        // false 

// add a new method 
Book.prototype.sayHi = function() { 
    console.log("Hi"); 
}; 

book1.sayHi();                        // outputs "Hi" 
book2.sayHi();                        // outputs "Hi" 

The code above generates the following result.

Built-in Object Prototypes

We can use prototypes to modify the built-in objects from the JavaScript engine.

The following code shows how to add a new method for arrays by modifying Array.prototype.


Array.prototype.sum = function() { /* ww w.  j a  v a2  s  .  co  m*/
    return this.reduce(function(previous, current) { 
        return previous + current; 
    }); 
}; 

var numbers = [ 1, 2, 3, 4, 5, 6 ]; 
var result = numbers.sum(); 

console.log(result);

The code above generates the following result.

The following code shows how to add new method for string value.


String.prototype.capitalize = function() { 
    return this.charAt(0).toUpperCase() + this.substring(1); 
}; 

var message = "hello world!"; 
console.log(message.capitalize());

The code above generates the following result.