Peter
Peter

Reputation: 48978

Should I use polymorphism in javascript?

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?

Upvotes: 32

Views: 14390

Answers (5)

ZER0
ZER0

Reputation: 25332

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).

Upvotes: 43

Weston
Weston

Reputation: 1857

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.

Upvotes: 4

Johnno Loggie
Johnno Loggie

Reputation: 149

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.

Upvotes: 4

Joseph
Joseph

Reputation: 119867

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());

Upvotes: 8

Weston
Weston

Reputation: 1857

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.

Upvotes: 13

Related Questions