23
var A=function(){
};

$.extend(A.prototype, {
    init:function(){
        alert('A init');
    }
});
var B=function(){

};

$.extend(B.prototype,A.prototype,{
    init:function(){
        alert('B init');
    }
});
var p=new A();
p.init();
var x=new B();
x.init();

is the above the best way to create class and inheritance in jQuery? In B's init how do I invoke parent's init (similar to super.init() in OO languages)?

1
  • Searching for a way to do this too, none of the provided answers satisfied me. I offer an alternative jQuery solution below, that leverages $.extend and $.proxy. Commented Jul 15, 2015 at 1:56

6 Answers 6

20

For OO, it's best to look outside jQuery. jQuery is based on collections returned by selectors.

If you want classes, some choices are Base2, Joose, and JS.Class.

Sign up to request clarification or add additional context in comments.

2 Comments

How is this an accepted answer? Q: "Is this the best way to do X in jQuery?" A: "Don't use jQuery." For some of us that's not really an option.
@umassthrower The answerer is not suggesting that he should not use jQuery, he is suggesting that jQuery does not provide a solution for classes. Any of the options mentioned can coexist with jQuery.
18

John Resig created a snippet for simple inheritance here. http://ejohn.org/blog/simple-javascript-inheritance/

he stores the super class to a _super variable so you can call it like such

this._super();

you can reference his code snippet to get a better idea of what he another helpful post is: http://alexsexton.com/?p=51

Comments

5

How to invoke parent's methods:

var B=function(){
    A.call(this);
};

$.extend(B.prototype,A.prototype,{
        init:function(){
                A.prototype.init.call(this);
                alert('B init');
        }
});

Comments

5

If you don't want to depend on any other libraries, you can do this:

function A() {}
A.prototype.foo = function() {};

function B() {
    A.call(this);
    //Or, if there are arguments that need to be passed to A(),
    //this might be preferable:
    //A.apply(this, arguments);
}

B.prototype = new A();

//Or, if the browser supports ECMAScript 5 and/or you have a shim for Object.create,
//it would be better to do this:
B.prototype = Object.create(A.prototype);

$.extend(B.prototype, {
   //set the constructor property back to B, otherwise it would be set to A
   constructor: B,
   bar: function() {}
});

Make sure to define any properties in the constructor rather than on the prototype, e.g.:

function A() {
    this.baz = null;
}

This avoids having unintentionally shared prototype properties.

There are some libraries that make prototypal inheritance easier:

Notes:

  • Any time a prototype is replaced, including by extension, it's a best practice to set its constructor property back to the correct constructor. That's why we set B.prototype.constructor to B. If you were replacing A.prototype you should do it like this:

...

A.prototype = {
    constructor: A,
    foo: function() {}
    //other methods...
}
  • B.prototype = Object.create(A.prototype) is preferred over B.prototype = new A() because it helps you detect it early if you forgot to call A() from B()'s constructor; it also allows A() to have required parameters. You'll need a shim for older browsers; the simplest shim (although it doesn't support the full Object.create spec) is at the bottom of this page: http://javascript.crockford.com/prototypal.html.

Comments

0

I use the same pattern and I like its conciseness.

About the lack of the "super" keyword, that's not really a problem. Thanks to Function.prototype.call() operator, you can call any function within the context of any object. So the sequence to call A.prototype.init() from B.prototype.init() is:

A.prototype.init.call(this, some parameters ...);

Also, don't forget that you may call A constructor from B constructor like this:

B = function(key, name) {
    A.call(this, key);
    this.name = name;
};

An experimented JS coder will know what happens.

So to conclude: not perfect but close enough.

Comments

0

I was looking for something similar. None of the answers given really appealed to me, so I finally had a crack at it myself...

http://jsfiddle.net/tn9upue0/1/

Example Classes

  • $.Animal() creates a generic animal, with a default of 4 legs, that can be passed a name in it's options, and can describe itself. $.Dog() is a subclass of Animal that goes "woof", and may know some tricks. $.Cat() is a subclass of Animal that goes "meow". $.Bird() is a subclass of Animal that has 2 legs and goes "tweet".

Class implementation

  • Each animal subclass creates an instance of $.Animal called parent, which can be used later to call methods of the parent. When calling a parent method, context can be important. When it is, the method should be called via $.proxy() passing this as the context.

Example output

My name is unknown. I am an animal with 4 legs.

My name is Rover. I am an animal with 4 legs. I say "woof". I can sit, stay, and roll over.

My name is Mittens. I am an animal with 4 legs. I say "meow".

My name is unknown. I am an animal with 2 legs. I say "tweet".

Sample code

$.Animal = function (options) {
    return {
        options: options || {},

        _getName: function () {
            return this.options.name || 'unknown';
        },

        _getLegs: function () {
            return 4;
        },

        describe: function () {
            return 'My name is ' + this._getName() + '. I am an animal with ' + this._getLegs() + ' legs.';
        }
    }
};

$.Dog = function (options) {
    var parent = $.Animal(options);
    return $.extend({}, parent, {
        describe: function () {
            var s = $.proxy(parent.describe, this)() + ' I say  "woof".';
            if (this.options.tricks) {
                s += ' I can ' + this.options.tricks + '.';
            }
            return s;
        }
    });
};

$.Cat = function (options) {
    var parent = $.Animal(options);
    return $.extend({}, parent, {
        describe: function () {
            return $.proxy(parent.describe, this)() + ' I say  "meow".';
        }
    });
};

$.Bird = function (options) {
    var parent = $.Animal(options);
    return $.extend({}, parent, {
        _getLegs: function () {
            return 2;
        },

        describe: function () {
            return $.proxy(parent.describe, this)() + ' I say "tweet".';
        }
    });
};

var animal = $.Animal(),
    rover = $.Dog({name: 'Rover', tricks: 'sit, stay, and roll over'}),
    mittens = $.Cat({name: 'Mittens'}),
    bird = $.Bird();
$('#out').html(
    animal.describe() + '<br>' +
        rover.describe() + '<br>' +
        mittens.describe() + '<br>' +
        bird.describe()
);

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.