1

I find this is most recommended way to do inheritance in javascript.

function extend(Child, Parent) {
 var F = function(){};
 F.prototype = Parent.prototype;
 Child.prototype = new F();
}

what if I already have methods in child's prototype, aren't they will overwrite, shouldn't we preserve them.

function extend(Child, Parent) {
 var c = child.prototype;
 var oldProto = new C();  
 var F = function(){};
 F.prototype = Parent.prototype;
 Child.prototype = new F();
 for(var i in oldProto ){
   Child.prototype[i] = oldProto[i]  
 }  
}
3
  • "what if i already have methods in child's prototype" - don't do that. Commented Oct 18, 2012 at 8:40
  • @Alnitak what if i am willing to do 2 inheritance extend(human, monkey) than extend(human, donkey). wouldn't you lost all the monkey properties Commented Oct 18, 2012 at 8:52
  • multiple inheritance? - don't do that ;-) Commented Oct 18, 2012 at 8:57

3 Answers 3

2

I'm not sure if this is any good to you, but it's well important to remember: prototypes are not the same things as classes. What you're doing is trying to make JS behave like a traditional OO language, which is trying to teach a dolphin to dance ballet, or forcing a tiger to become vegan: Admirable, but destined to end in tears.

I can't really see why you'd want to use the extend function to do whatever it is you're trying to do. Why not simply use this:

function Parent()
{};
function Child()
{};
//augment parent proto
Parent.prototype.parentMethod1 = function()
{};
//set Child's proto to Parent
Child.prototype = new Parent();
Child.prototype.constructor = Child;
//Then augment the Child's prototype
Child.prototype.childMethod1 = function()
{};
var foo = new Child();
foo.parentMethod1();//works
foo.childMethod1();//works, too

IMO, this solves the problem entirely. Sure, it's a tad more verbose, but OOP always is.

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

4 Comments

"What you're doing is trying to make JS behave like a traditional OO language, which is trying to teach a dolphin to dance ballet, or forcing a tiger to become vegan" By the way Google does it successfully in many of their web applications code.google.com/p/closure-library/source/browse/trunk/closure/…
@bjornd: Success is a relative term. Sure, you can implement such features. But in truth, I don't like such constructions: the way they mimic multiple inheritance works in a direct method-to-proto assignment scenario, but what if your prototype method is the return value of an IIFE... honestly, a lot of people struggle with closures as it is, I dread to think what they'll make of GC-ing closure vars, referenced in "extended" prototype methods... Bottom line: google's code works, in theory, the way it's used can cause headaches still. I agree with Alnitak: just don't.
A phrase often used is use the right tool for the job. When you try to force JS to behave like another language, you should consider either using a different language (which is not really an option) or evaluate the tool (JS). For all it's downsides, JS still has a lot going for itself. I'd like it if more people actually knew what JS is capable of, in the right hands. It's a functional language, not a traditional OO language: use it accordingly
The pattern from the original post is standard de-facto in the modern JS world. It's used in Ext JS, YUI, Google Closure, etc. I'd like people to learn the useful stuff, not the theoretical mantras.
0

The pattern you're trying to achieve is called multiple inheritance. And it's highly not recommended for the use because of the issue you're experiencing, called diamond problem. Just use mixin pattern instead.

3 Comments

This hasn't got anything to do with the deadly diamond-thing. His problem is that, by extending, the Child.prototype.methodx will be lost, because Child.prototype is being reassigned to an instance of Parent. He needs the methods of Parent, without loosing those assigned to the Child.prototype. BTW: JavaScript doesn't support multiple inheritance, only prototype chaining
@EliasVanOotegem In the comment by niteshsharma you can see that he is trying to do multiple inheritance.
@bjornd you're half right. He is trying to implement multiple inheritance, but in a prototypical language like JS the diamond problem doesn't exist because it's only methods that are "inherited", not instance data.
0

The code below is the one of the best I have seen for doing inheritance in JavaScript.

Object.create(proto [, propertiesObject ]) is discussed on MDN here.

Below, Jon defines a base empty object called ExtendBase then adds a function property called extend which is not enumerable which takes as its argument a single new object.

That object should contain enumerable properties such as methods and data that will be added to the base object.

He gets all the enumerable properties from the passed object, then creates an array of the necessary descriptors to pass into Object.create using those properties' names. He then uses the parent object as the prototype and resultant descriptors as new properties to be added to the child object directly in the Object.create() call.

As you can see, you can use an object argument with properties, including methods, to extend a parent without losing that passed object's properties with the result being a child object with the parent as the prototype and the enumerable objects of the passed object added directly to the child.

However, this maintains a clean prototype chain while intending to extend parent objects using other objects which are created sanely to extend the parent into a new child in a way that makes sense:

Live sample here (Press F12 in Chrome for console output, or use FireBug in FireFox, etc.)

JavaScript:

// Original Author:  FireFly - Jonas Höglund - ##javascript channel
// on irc.freenode.net - see THANKS File.  Updated to private data
// members and passable initial parameters by Scott Sanbar

///////////////
// Library code
///////////////

var ExtendBase = {};

Object.defineProperty(ExtendBase, 'extend', {
    enumerable:false, value:function (obj) {
        'use strict';

        var descs = {};

        Object.getOwnPropertyNames(obj).forEach(function (key) {
            descs[key] = Object.getOwnPropertyDescriptor(obj, key)
        });

        return Object.create(this, descs);
    }
});

///////////////
// Sample Usage
///////////////

function PersonObj(nam) {

    return {
        name:new function () {

            var name = nam;

            this.set = function (value) {
                name = value;
            };

            this.get = function () {
                return name;
            }
        },

        // A person can tell you its name.
        talk:function () {
            return "Hello, I'm " + this.name.get();
        }
    }
}
;

function WorkingPersonObj(occ) {

    return {

        occupation:new function () {

            var occupation = occ;

            this.set = function (value) {
                occupation = value;
            };

            this.get = function () {
                return occupation;
            }
        },

        // A working person also tells you their occupation when they talk.
        talk:function () {
            return Person.talk.call(this) + " and I am a " + this.occupation.get();
        }
    }
}
;

var hush = {

    hush:function () {
        return "I am supposed to be quiet";
    }
};

var Person = ExtendBase.extend(new PersonObj('Harry'));
var WorkingPerson = Person.extend(new WorkingPersonObj('wizard'));

var wp1 = WorkingPerson.extend(hush);

console.log(wp1.talk()); // "Hello, I'm Harry and I am a wizard"
console.log(wp1.hush()); // "I am supposed to be quiet"
wp1.name.set("Elijah");
wp1.occupation.set("prophet");
console.log(wp1.talk()); // "Hello, I'm Elijah and I am a prophet"
console.log(wp1.name.get());
console.log(wp1.occupation.get());

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.