27

Inheritance, Polymorphism, and Encapsulation are the three most distinct, important features of OOP, and from them, inheritance has a high usage statistics these days. I'm learning JavaScript, and here, they all say that it has prototypal inheritance, and people everywhere say that it's something far different from classical inheritance.

However, I can't understand what's their difference from the point of practical usage? In other words, when you define a base class (prototype) and then derive some subclasses from it, you both have access to functionalites of your base class, and you can augment functions on the derived classes. If we consider what I said to be the intended result of inheritance, then why should we care if we're using prototypal or classic version?

To clear myself more, I see no difference in the usefulness and usage patterns of prototypal and classic inheritance. This results in me having no interest to learn why they are different, as they both result in the same thing, OOAD. How practically (not theoretically) prototypal inheritance is different from classical inheritance?

4 Answers 4

6

Recent blog post about JS OO

I believe what your comparing is classical OO emulation in JavaScript and classical OO and of course you can't see any difference.

Disclaimer: replace all references to "prototypal OO" with "prototypal OO in JavaScript". I don't know the specifics of Self or any other implementation.

However prototypal OO is different. With prototypes you only have objects and you can only inject objects into other objects prototype chain. Whenever you access a property on an object you search that object and any objects in the prototype chain.

For prototypal OO there is no notion of encapsulation. Encapsulation is a feature of scope, closures and first class functions but has nothing to do with prototypal OO. There is also no notion of inheritance, what people call "inheritance" is actually just polymorphism.

It does however have polymorphism.

For example

var Dog = {
  walk: function() { console.log("walks"); }
}

var d = Object.create(Dog);
d.walk();

Clearly d has access to the method Dog.walk and this exhibits polymorphism.

So actually there is a big difference. You only have polymorphism.

However as mentioned, if you desired to do so (I have no idea why you would) you can emulate classical OO in JavaScript and have access to (restricted) encapsulation and inheritance.

6
  • 1
    @Rayons, Google for prototypical inheritance and you'll see that prototypal inheritance comes up. Even from Yahoo! Commented Aug 8, 2011 at 4:30
  • @Saeed inheritance is a vague term and commonly misused. What they mean with "inheritance" I label "polymorphism". The definitions are too vague.
    – Raynos
    Commented Aug 8, 2011 at 8:01
  • No @Rayons, I meant the word prototypal is the correct term, not prototypical. I didn't talk about inheritance :) Commented Aug 8, 2011 at 8:57
  • 1
    @Saeed that's one of those typos my mind just blanks out. I don't pat attention to that
    – Raynos
    Commented Aug 8, 2011 at 11:07
  • 1
    Hmm.. terminology. ick. I would call the way that javascript objects are related to their prototypes "delegation". Polymorphism seems to me to be a lower-level concern, based on the fact that a given name may point to different code for different objects. Commented Aug 8, 2011 at 19:52
15

Classical inheritance inherits the behavior, without any state, from the parent class. It inherits the behavior at the moment the object is instantiated.

Prototypal inheritance inherits behavior and state from the parent object. It inherits the behavior and state at the moment the object is called. When the parent object changes at run-time, the state and behavior of the child objects are affected.

The "advantage" of prototypal inheritance is that you can "patch" state and behavior after all your objects are instantiated. For example, in the Ext JS framework it's common to load "overrides" that patch the framework's core components after the framework has been instantiated.

4
  • 4
    In practice, if you're inheriting state, you're setting yourself up for a world of hurt. Inherited state will become shared if it lives on another object. Commented Aug 8, 2011 at 19:53
  • 1
    It occurs to me that in javascript there really is no concept of behavior separate from state. Aside from the constructor function all behavior can be assigned/modified post-object-creation just like any other state. Commented May 21, 2012 at 7:16
  • So Python doesn't have classical inheritance? If I have class C(object): def m(self, x): return x*2 and then instance = C() then when I run instance.m(3) I get 6. But if I then change C so C.m = lambda s, x: x*x and I run instance.m(3) I now get 9. The same goes if I make a class D(C) and change a method on C then any instances of D receive the changed method as well. Am I misunderstanding or does this mean that Python does not have Classical inheritance according to your definition?
    – mVChr
    Commented Aug 8, 2013 at 8:34
  • @mVChr: You're still inheriting behavior and not state in that case, which points to classical inheritance, but it does point to an issue with my definition of "inherits the behavior the moment the object is instantiated". I'm not quite sure how to correct the definition. Commented Aug 8, 2013 at 11:41
9

First: Most of the time, you'll be using objects, not defining them, and using objects is the same under both paradigms.

Second: Most prototypal environments use the same kind of division as class based environments -- mutable data on the instance, with methods inherited. So there's very little difference again. (See my answer to this stack overflow question, and the Self Paper Organizing Programs Without Classes. Look at Citeseer for a PDF version.)

Third: Javascript's dynamic nature has a much bigger influence that the kind of inheritance. The fact that I can add a new method to all instances of a type by assigning it to the base object is neat, but I can do the same thing in Ruby, by reopening the class.

Fourth: The practical differences are small, while the practical issue of forgetting to use new is much bigger -- that is, you're far more likely to be affected by missing a new than you are to be affected by the difference between prototypal and classical code.

All that said, the practical difference between prototypal and classical inheritance is that your things-that-hold-methods (classes) are the same as your things-that-hold-data (instances.) This means that you can build up your classes piecemeal, using all the same object manipulation tools that you would use on any instance. (This is, in fact, how all of the class-emulation libraries do it. For a not-quite-like-all-the-others approach, look at Traits.js). This is primarily interesting if you are metaprogramming.

1
  • yay, best answer IMO!
    – Aivar
    Commented May 18, 2012 at 22:13
0

Prototypal inheritance in JavaScript is different from classes in these important ways:

Constructors are simply functions that you can call without new:

function Circle (r, x, y) { 
  //stuff here
}
Var c = new Circle();
Circle.call(c, x, y, z); //This works and you can do it over and over again.

There are no private variables or methods, at best you can do this:

function Circle (r, x, y) {
  var color = 'red';
  function drawCircle () {
    //some code here with x, y and r
  }
  drawCircle();
  this.setX = function (x_) {
    x = x_;
    drawCircle();
  }

}
Circle.prototype.getX = function () {
   //Can't access x!
}

In the previous example you can't extend the class meaningfully if you're resorted to fake private variables and methods and in addition any public methods you've declared will be recreated every time a new instance is created.

5
  • You can extend the "class" meaningfully. You just can't access the local variables color, r, x, y and drawCircle that are bound to the lexical scope of Circle
    – Raynos
    Commented Aug 7, 2011 at 22:14
  • It's true, you can, but you can't do it without creating a bunch of 'public' methods added to the context that are created every time you create an instance.
    – Bjorn
    Commented Aug 7, 2011 at 23:27
  • This is a very strange pattern you're using there. Circle.call() as a constructor? It looks like you're trying to describe "functional objects" (a misnomer...) Commented Aug 8, 2011 at 19:54
  • It's not something I'd ever do, I'm just saying it is possible to call the constructor over and over again with JavaScript but not in languages with traditional classes.
    – Bjorn
    Commented Aug 9, 2011 at 0:34
  • 1
    But how are these differences 'important'? I don't see constructing objects by calling a function, not using 'new', as 'important', just a small syntax difference. Likewise, not having private variables isn't fundamentally different, just a small difference. Plus, you can have (something similar to) private variables, in the way you describe.
    – Roel
    Commented May 14, 2012 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.