Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differences Between Hooking a Function onto Prototype or Not

What is the differences between:

function Gandalf() {
    this.color = 'grey';
}

Gandalf.prototype.comeBack = function() {
    this.color = 'white';
}

And:

function Gandalf() {
    this.color = 'grey';

    this.comeBack = function() {
        this.color = 'white';
        return this;
    };
}

And under which circumstances should I hook the method onto the prototype, or not?

like image 223
gsklee Avatar asked Feb 17 '23 02:02

gsklee


1 Answers

Alright Agent Kay, I'll approach this question in a different way than Esailija did. Let's begin with simple objects. For example say you already have an object called gandalf:

var gandalf = {
    color: "grey",
    comeBack: function () {
        this.color = "white";
        return this;
    }
};

There are no constructors in this code. Hence this code is easy to understand. Am I right or am I right?


Alright, now I'm going to do something awesome. I'll create radagast from gandalf:

var radagast = Object.create(gandalf);

radagast.color = "brown";

What's happening here? Let's break it up:

  1. We create a new object called radagast from gandalf using Object.create. Hence radagast inherits from gandalf.
  2. We set the color of radagast to brown instead of grey.

To make it even more simple imagine you and I had the following conversation:

I: Hey Agent Kay, I met Radagast yesterday.

U: Who's Radagast?

I: Hmm... do you know who's Gandalf?

U: Yes, I do.

I: Well Radagast is just like Gandalf except that he's brown instead of white.

This is exactly how inheritance works in JavaScript. You see JavaScript has prototypal inheritance. In prototypal inheritance objects inherits from other objects. In this case radagast inherited from gandalf.


Now they way prototypal inheritance is usually implemented in JavaScript is weird. I call it the constructor pattern of prototypal inheritance. For example, take your code:

function Gandalf() {
    this.color = "grey";
}

Gandalf.prototype.comeBack = function() {
    this.color = "white";
    return this;
};

Now when you create an instance of Gandalf what object does the instance inherit from? It inherits from Gandalf.prototype:

var gandalf = new Gandalf;
alert(Object.getPrototypeOf(gandalf) === Gandalf.prototype); // true

What's happening when you say new Gandalf is:

var gandalf = Object.create(Gandalf.prototype);
Gandalf.call(gandalf);

If you expand Gandalf.call(gandalf) the you get:

var gandalf = Object.create(Gandalf.prototype);
gandalf.color = "grey";

Now take your second example:

function Gandalf() {
    this.color = "grey";

    this.comeBack = function() {
        this.color = "white";
        return this;
    };
}

In this case when you create an instance of Gandalf you're essentially doing this:

var gandalf = Object.create(Gandalf.prototype);

gandalf.color = "grey";

gandalf.comeBack = function () {
    this.color = "white";
    return this;
};

Hence every time you create a new Gandalf you create a new function comeBack. Thus if you call new Gandalf 10 times you'll have 10 different comeBack functions as well.

Compared to this in the first example since comeBack is defined on Gandalf.prototype, every time we call new Gandalf we get a new object which inherits from Gandalf.prototype. Hence there's only one comeBack function which is shared amongst all instances of Gandalf. Isn't that better?


Essentially think of your first example like this:

var gandalfPrototype = {
    create: function () {
        var gandalf = Object.create(this);
        gandalf.color = "grey";
        return gandalf;
    },
    comeBack: function () {
        this.color = "white";
        return this;
    }
};

var gandalf = gandalfPrototype.create(); // there's only one comeBack function

Similarly your second example is equivalent to this:

var gandalfPrototype = {
    create: function () {
        var gandalf = Object.create(this);

        gandalf.color = "grey";

        gandalf.comeBack = function () {
            this.color = "white";
            return this;
        };

        return gandalf;
    }
};

var gandalf = gandalfPrototype.create(); // there's 1 comeBack for each instance

Remember that when you use new before a function call you're actually inheriting from the prototype of the function. Not the function itself.


Finally I would like to say (because I'm a big fan of J.R.R. Tolkien) that this is the way I would write your code:

var wizard = {
    create: function (color) {
        var wizard = Object.create(this);
        wizard.color = color;
        return wizard;
    }
};

var gandalf = wizard.create("grey");

gandalf.comeBack = function () {
    this.color = "white";
    return this;
};

var saruman = wizard.create("white");
var radagast = wizard.create("brown");

Thank you for reading my answer.

like image 132
Aadit M Shah Avatar answered Feb 18 '23 18:02

Aadit M Shah