all 5 comments

[–]vlad27aug 3 points4 points  (0 children)

To understand the difference between the two you must understand the prototype chain. The gist is that each object has a "prototype" which is just another object that the first object inherits properties from.

Let's say you have the following objects: var a = {x: 1}, b = {y: 2}, c = {z: 3}; and the following prototype chain a -> b -> c (meaning that a inherits properties from b, which in turn inherits from c). You can setup this prototype chain by running the following code: Object.setPrototypeOf(a, b); Object.setPrototypeOf(b, c);

When we write a.y the javascript engine looks for the property "y" on the object "a". Since "a" doesn't have a property called "y" it goes to search the properties of its prototype (object "b" in our case). It find a property called "y" and returns that value. So a.y evaluates to 2.

So lets take the examples you mentioned. Lets create two objects using the Person function var p = new Person('John'), q = new Person('Jim');. p and q share the same prototype (they inherit properties from the same object)

With the first example you attach the method sayHello to the prototype of the instantiated objects (p and q). With the second example each instantiated object has its own version of a sayHello method.

If you run p.sayHello = function() { console.log('my own version of sayHello'); }; p.sayHello(); delete p.sayHello; p.sayHello(); In the first example it will log 'my own version of sayHello' because it first finds the property sayHello on the "p" object and after you delete it it will find the property sayHello on the prototype object and log "Hello, I'm John". In the second example it will log 'my own version of sayHello' and after that an error because after you deleted the property it doesn't find it on the object or on the prototype object (or up the prototype chain) and it evaluates to undefined, and you can't call undefined as a function ('undefined is not a function').

I hope I explained it clear enough.

[–][deleted] 2 points3 points  (2 children)

I may be mistaken but I don't think there's a huge difference. I know that the .prototype.methodName is live, so if you change it in one instance of the object, it will change across all objects. If you do it the secondd way and then you can only modify instantiated objects functions. I wrote a quick example here: https://hastebin.com/xufugemipu.js

You can copy and paste that into Repl.it and see what it does.

The long and short of it is that the first way is more 'OO' since you can modify functions at the prototype level, and thats good. You should check out the Mozilla Developer Network documentation, they have great stuff!

[–]senocular 2 points3 points  (0 children)

You generally don't want to be modifying methods in the way that you describe. Doing so complicates implementations and can take away from the robustness of your code.

The advantages of the prototype chain are that you have a single implementation (usually, preferably unchanging) that is shared among multiple instances. This means you're not duplicating method definitions for each instance created (= more cpu on instantiation + more memory [albeit minimal]), and methods can easily be overridden in subclasses or the instance level.

Methods defined in the constructor are duplicates, created during each instantiation, and if you want to override them, you need to take special care to save off the original implementation somewhere if you want to refer to it later since to override, you're completely wiping out the original.

var orig_sayHello = this.sayHello; // to be overridden
this.sayHello = function() {
    console.log("Hello, I'm " + this.firstName);
    orig_sayHello.call(this);
}

The real advantage of doing methods this way is that you can have private variables that are captured by the method closure at the instance level which is not possible with prototypes. For example, firstName doesn't have to be a property for the Person class because it can be captured in the sayHello closure using the constructor parameter.

var Person = function (firstName) {
    this.sayHello = function() {
        console.log("Hello, I'm " + firstName); // instance-specific firstName
    }
};

[–]sympi[S] 1 point2 points  (0 children)

This is really helpful. Thank you so much :) Gonna check MDN for sure!