3

Having the parent class:

function Animal() {
  // do something
}

Animal.prototype.walk = function() {
  alert('I am walking.');
};

and the child class:

function Lion() {
  // do something
}

if I want the Lion to inherit Animal's prototype a common practice is this:

Lion.prototype = new Animal();

// Set the constructor to Lion, because now it points to Animal
Lion.prototype.constructor = Lion;

Is this in any way different from this (as result not as performance)?

$.extend(Lion.prototype, Animal.prototype);

For non jquery developers: $.extend copies all the prototype methods and attributes, one by one from Animal to Lion.

I am not a big expert of inheritance in javascript. I usually use an MVC framework for front-end development where everything just works, but now I would love to understand also how inheriting the prototype works.

NOTE! I read many articles about the subject, I know there are many "plugins" that implements the Class functionality. This is not what I need. Please answer the question, not just link articles about the subject (except if that answers it).

Thank you!

Tamás Pap
  • 17,777
  • 15
  • 70
  • 102
  • 1
    `$.extend` in jQuery implements a **mixin** JavaScript pattern designed primarily to clone objects and add new props and methods; where modifying the former object doesn't affect the new one. Think of it as the new `Object.create` in Harmony, with one difference - `newObj = Object.create(oldObj)` makes `oldObj` the `__proto__` of the `newObj` – Om Shankar Jun 12 '13 at 04:47

5 Answers5

3

There's a difference, copying the properties between two prototypes doesn't make them "connected" to each other, i.e.:

$.extend(Lion.prototype, Animal.prototype);

// add one more method to the prototype
Animal.prototype.test = function() {
  alert('test');
};

var x = new Lion();
x.test(); // TypeError: Object <Lion> has no method 'test'

You wouldn't have this if you use new Animal() as the prototype for Lion, as demonstrated here.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
3

I recently wrote an article that explains Why Prototypal Inheritance Matters. It's a bit long but well worth the read.

To answer your question directly, yes Lion.prototype = new Animal is different from $.extend(Lion.prototype, Animal.prototype) because:

  1. In the first case you're using delegation.
  2. In the second case you're using concatenation.

The post I linked you to explains true prototypal inheritance (i.e. prototypal inheritance using the prototypal pattern).

This is how your program would look if you used true prototypal inheritance in JavaScript:

var animal = {
    create: function () {
        return this.extend();
    },
    walk: function () {
        alert("I am walking.");
    }
};

var lion = animal.extend({
    create: function () {
        return animal.create.call(this);
    }
});

Here the extend function is the one from the post I linked you to.

Contrast this with your code which uses the constructor pattern for prototypal inheritance.

Here's a fiddle which shows true prototypal inheritance in action: http://jsfiddle.net/6x4BU/

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 2
    Nice article (though I don't share all of your views). At least, putting enumerable properties on `Object.prototype` is bad practise! And those `clones` arrays will prevent garbage collection. – Bergi May 28 '13 at 07:24
  • @Bergi - That's a nice observation. I'll try to find a solution to that. Thank you. – Aadit M Shah May 28 '13 at 07:26
  • @Bergi - Would you mind posting the same comment on my blog so that others may read it as well. – Aadit M Shah May 28 '13 at 07:27
1

No they are not the same.

The first example the Lion prototype becomes an instance of Animal. That instance does inherit from the Animal prototype and will link back to that prototype. If the Animal prototype is modified the instance will be affected.

The second example is simply copying the properties from the Animal prototype and Lion will not be linked to the actual Animal prototype itself.

Stuart Wakefield
  • 6,294
  • 24
  • 35
0

As others have already mentioned, yes there is a difference.

In the first example, changes to the Animal prototype will change the behavior of Lion instances.

In the second example, Lion inherits the capabilities of Animal at the time of the $.extend() call.

The first way has some possibly harmful side-effects, though, in particular:

  • A change to Animal can ripple out and break Lion and its descendants. This dynamic changes property of delegate prototypes is usually considered a good thing, but when it's applied to multi-level inheritance, it frequently causes problems.

  • The first method doesn't allow for selective inheritance from Animal. It's all or nothing. You wanted the banana, but what you got was the gorilla, the banana, and the entire jungle. (This famous problem is called the gorilla/banana problem). The latter method lets you selectively inherit from Animal: $.extend(Lion.prototype, { run: Animal.prototype.run, sleep: Animal.prototype.sleep });

  • instanceof breaks with concatenation -- but instanceof is not reliable in any case. If you reassign the Animal prototype, it will break. If you try to use it across execution contexts, it breaks. In other words, don't use instanceof, regardless of which inheritance method you choose.

Constructor functions aren't necessary at all. You could just create an object literal called animal and do this:

lion = Object.create(animal);

Even better, put that in a factory function:

function lion(options) {
  return $.extend(Object.create(lion), options);
}

Factory functions have lots of advantages over constructor that I won't go into here. You can see more details in my answer on this post: Constructor function vs Factory functions

Community
  • 1
  • 1
Eric Elliott
  • 4,711
  • 1
  • 25
  • 33
0

This is a basic prototype inheritance in pure JavaScript

// base class declaration
function Animal (arg) {
    this.arg = arg;
}

// just a method in the Animal class, it can be whatever you want
Animal.prototype.roar = function () {
    alert(this.arg);
};

// object that inherits the base class
function Lion (arg) {
    // the call to the super constructor
    Animal.call(this, arg);
}

// the prototypical inheritance
Lion.prototype = Object.create(Animal.prototype);
// the constructor needs to be set so that it does not show as the base constructor
// otherwise the constructor for all instances of Lion will show as Animal
Lion.prototype.constructor = Lion;

var symba = new Lion('the lion is roaring');

symba.roar();