Augmenting Built-in Objects

Augmenting built-in objects through the prototype is a very powerful technique and you can use it to shape JavaScript any way you like. But modifying core objects could only confuse the user of the library and create unexpected errors.

The JavaScript changes and browsers come up with new versions that support more features.

To reverse strings there is no built-in reverse() method for string objects. After all, arrays have reverse(). You can easily add this reverse() method to the String prototype, borrowing Array.prototype.reverse(). The below code uses split() to create an array from a string, then calls the reverse() method on this array, which produces a reversed array.

String.prototype.reverse = function() {
    return Array.prototype.reverse.apply(this.split('')).join('');
}
"Stoyan".reverse();

"nayotS"
Best Practice

When you decide to augment the prototype of built-in objects with a new property check for existence of the new property before implementing it.

if (!String.prototype.reverse) {
    String.prototype.reverse = function() {
        return Array.prototype.reverse.apply(this.split('')).join('');
    }
}
Points to remember

Here are two interesting behaviors to consider when dealing with prototypes:

  • prototype.constructor is not reliable
  • The prototype chain is live until the prototype object is completely replaced.

Creating a simple constructor function and two objects.

function Dog(){this.tail = true;}

var benji = new Dog();

var rusty = new Dog();

Even after you create the objects, you can still add properties to the prototype and the objects will have access to the new properties. Let's throw in the method say():

Dog.prototype.say = function() {
    return 'Woof!';
}

Both objects have access to the new method:

benji.say();
"Woof!"

rusty.say();
"Woof!"

If you check your objects, asking which constructor function was used to create them, they'll report it correctly.

benji.constructor;
Dog()

rusty.constructor;
Dog()

But if you ask what is the constructor of the prototype object, you'll also get Dog(), which is not quite correct. The prototype is just a normal object created with Object(). It doesn't have any of the properties of an object constructed with Dog().

benji.constructor.prototype.constructor
Dog()

typeof benji.constructor.prototype.tail
"undefined"

Now overwrite the prototype object with a new object.

Dog.prototype = {paws: 4, hair: true};

Now the old objects do not get access to the new prototype's properties, they still keep the secret link pointing to the old prototype object.

typeof benji.paws
"undefined"

benji.say()
"Woof!"

typeof benji.__proto__.say
"function"

typeof benji.__proto__.paws
"undefined"

Any new objects you create from now on will use the updated prototype.

var lucy = new Dog();
lucy.say()
TypeError: lucy.say is not a
function
lucy.paws
4

The secret __proto__ link points to the new prototype object.

typeof lucy.__proto__.say
"undefined"

typeof lucy.__proto__.paws
"number"

Now the constructor property of the new objects reports wrongly. It should point to Dog(), but instead it points to Object().

lucy.constructor
Object()

benji.constructor
Dog()

The prototype of the constructor is the confusing part.

typeof lucy.constructor.prototype.paws "undefined" typeof benji.constructor.prototype.paws "number"

The following code fixed all of the unexpected behavior described above.

Dog.prototype = {paws: 4, hair: true}; Dog.prototype.constructor = Dog;

Note
When you overwrite the prototype, it is a good idea to reset the constructor property.
Related Tutorial
Follow Us
https://www.facebook.com/Rookie-Nerd-638990322793530 https://twitter.com/RookieNerdTutor https://plus.google.com/b/117136517396468545840 #
Contents +