Should I use polymorphism in javascript?

14,242

Solution 1

As said, JavaScript is a dynamic typed language based on prototypal inheritance, so you can't really use the same approach of typed languages. A JS version of what you wrote, could be:

function Shape(){
  throw new Error("Abstract class")
}

Shape.prototype.printSurface = function () {
  throw new Error ("Not implemented");
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape.prototype);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

Then, in your app:

var obj = new Circle();

if (obj instanceof Shape) {
    // do something with a shape object
}

Or, with duck typing:

if ("printSurface" in obj)
    obj.printSurface();

// or

if (obj.printSurface)
    obj.printSurface();

// or a more specific check
if (typeof obj.printSurface === "function")
    obj.printSurface();

You cold also have Shape as object without any constructor, that it's more "abstract class" like:

var Shape = {
    printSurface : function () {
        throw new Error ("Not implemented");
    }
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

Notice that in this case, you can't use instanceof anymore, so or you fallback to duck typing or you have to use isPrototypeOf, but is available only in recent browsers:

if (Shape.isPrototypeOf(obj)) {
    // do something with obj
}

Object.create is not available in browser that doesn't implement ES5 specs, but you can easily use a polyfill (see the link).

Solution 2

The "pattern" in play here would be "interface". As long as all the objects in the myshapes collection implement the printSurface() method, you will be fine.

Since Javascript is a dynamically typed language, the objects in a collection don't need to be related at all.

Solution 3

i know this can be done with prototypes but i am not a master of using it. i prefer the object literal approach (easier to visualize and has a "private" scope)

//shape class
var shape = function() {
    //return an object which "shape" represents
    return {
        printSurface: function() {
            alert('blank');
        },
        toInherit: function() {
            alert('inherited from shape');
        }
    }
};

//rect class
var rect = function() {
    //inherit shape
    var rectObj = shape();

    //private variable
    var imPrivate = 'Arrr, i have been found by getter!';

    //override shape's function
    rectObj.printSurface = function(msg) {
        alert('surface of rect is ' + msg);
    }

    //you can add functions too
    rectObj.newfunction = function() {
        alert('i was added in rect');
    }

    //getters and setters for private stuff work too
    rectObj.newGetter = function(){
        return imPrivate;
    }

    //return the object which represents your rectangle
    return rectObj;
}



//new rectangle
var myrect = rect();

//this is the overridden function
myrect.printSurface('foo');

//the appended function
myrect.newfunction();

//inherited function
myrect.toInherit();

//testing the getter
alert(myrect.newGetter());

Solution 4

As Weston says, if you don't have the need for inheritance then the duck-typed nature of a dynamic language such as Javascript gives you polymorphism since there is no requirement in the language itself for a strongly typed base class or interface.

If you do want to use inheritance and do things like calling a superclass's implementation easily then this can be achieved with prototypes or object literals as shown by Joeseph.

Another thing would be to look at Coffescript since this compiles down to Javascript giving you all the OO goodness in a simple syntax. It will write all of the bollerplate prototyping stuff for you. The disadvantage is that it adds this extra compilation step. That said writing a simple class hierarchy like your example above and then seeing what javascript pops out as a result helps show how it can all be done.

Solution 5

On another note. If you want to program Javascript in an OO style using classes, you could look into the many "class-systems" for Javascript. One example is Joose (http://joose.it).

Many client side frameworks implement their own class system. An example of this is ExtJS.

Share:
14,242
Peter
Author by

Peter

SOreadytohelp Make everything as simple as possible.. (but not simpler!) Albert Einstein The irrationality of a thing is no argument against its existence, rather a condition of it. Friedrich Nietzsche

Updated on June 13, 2022

Comments

  • Peter
    Peter about 2 years

    I am a programmer who has programmed in several languages, both functional and OO oriented. I programmed some Javascript too, but never used (or had to use) polymorphism in it.

    Now, as kind of a hobby project, I would like to port some apps that were written in Java and C# that heavily use polymorhpism to Javascript.

    But at a first glance I read lots of 'It's possible but ...'

    So is there an alternative to it?

    An example of what I would like to write in JS in pseudolang :

    abstract class Shape{ { printSurface() } ;  }
    
    class Rect : Shape() {  printSurface() { print (sideA*sideB}}
    
    class Circle : Shape() {  printSurface() { print { pi*r*r }}
    
    TheApp { myshapes.iterate(shape s) {s.printSurface() } }
    

    So a classic polymorphic case : iterating over baseclass.

    I would like to achieve this kind of behaviour. I know it is polymorhism, but are there any other 'patterns' that I am overlooking that achieve this kind of behaviour or should I study the inheritance possibilities in Javascript?