Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'd like to know what you think about my implementation of inheritance. It's pretty small and intuitive I think, but I don't know if there are any drawbacks.

I really want to keep it as simple as possible, therefore I don't want to use any libraries.

Actual code:

Object.prototype.__extends = function __extends(parent){
    var child = this;
    if(parent){
        child.prototype = new parent();
        child.prototype.__super = function __super(){
            if(child.prototype[arguments.callee.caller.name]){                
                return child.prototype[arguments.callee.caller.name].apply(this,arguments);
            }else{
                return child.prototype.constructor.apply(this,arguments);
            }
        }
    }
    return child;
}

Usage:

function Parent(args) {
    // set up Parent class
    this.someFunction = function someFunction(args){
        // do something
    }
}

Child = function Child(args){
   this.__super(args);  // not needed if parent constructor has no arguments
   // set up child class
   this.someFunction = function someFunction(args){ // no anonymous function here!
       this.__super(args); // calls Parent.someFunction !
       // do something else
   }
}.__extends(Parent);  // This is where the magic happens

child = new Child(args);

Example on JSFiddle

Update

I wanted to add some information on why I pursued this approach and what is actually happening in the code.

I originally created this code to have a way of inheritance that resembles inheritance in other languages (primarily Java) and is therefore easy to understand for most people.

I know it's not thought of as best-practice to inherit from functions via the new keyword but in this special case, where it should feel more like Java, I think this was the way to go. And if I recall correctly frameworks like prototype.js do so as well.

What annoyed me the most in classical inheritance in JavaScript was that everything was decentralized. First you define your constructor function, then you define the methods for you parent class and later you describe the inheritance.

I wanted to give JavaScript inheritance the feeling of classes.

Description

As anyone probably sees on first sight, I'm doing something evil here. I'm extending the Object prototype. I could have extended the Function prototype instead of the Object prototype but I don't think this is less evil.

What the __extends function does is, it creates a new instances of the parent object in order to use it as the prototype of the child. The new keyword enables us to write classes in the way I did above.

Additionally the child gets the __super function which is used to reference the parents functions.

If the caller of the __super function doesn't have a counterpart (same name) on the parent side, the parents constructor is called. If there is indeed a counterpart, it is called.

The arguments given to the __super function are redirected to the function that really should be called using .apply().

The return child at the end is needed to be able to put the .__extends() on the end of your "class" definition.

share|improve this question
    
I've rolled back this post as large code edits were made after receiving the first answer. Please keep the original embedded code intact. –  Jamal Jul 18 '14 at 13:04

1 Answer 1

First off, this code is a bit hard to follow and certainly not a conventional way of doing things in Javascript. Can you explain why you've chosen such a unique way to do it? What advantages are you seeking by doing it differently than one of the more "classic" and common and known ways of doing it?

Several comments:

  1. Object.create() is preferred for creating the object to assign to your subclass prototype rather than using new as it has fewer side effects (e.g. it doesn't run the constructor).

  2. Your code won't run in strict mode because of the use of .callee. Writing your code to be "strict mode safe" has a lot of benefits and no downsides that I know of.

  3. Your comments lead me to believe that you think you don't have to call parent constructors if there are no constructor arguments, but that is not necessarily the case.

  4. You appear to be attempting to make javascript inheritance look and work like inheritance in other languages. In my experience (I initially went this route too), that is a mistake. Javascript is a prototype-based language. It works differently than languages like C++ and Java and trying to make it look like a non-prototype-based language is not the right approach in the long run. It may feel more familiar in the short run to someone learning javascript, but in my opinion, that is not the real goal here and as soon as you feel more comfortable with how Javascript works, you won't feel like making JS look like some other language is the goal.

  5. Your code example seems to be avoiding using the object prototype for methods. There are some advantages to using the prototype. I'd suggest you read here and here and here.


Here's a fairly simple method of inheritance done a more common way in javascript, defining the constructor, putting methods on the prototype, setting up the inheritance, etc...). That's how a prototype-based language generally works. I use one utility function here to reuse some common elements of inheriting.

Working demo: http://jsfiddle.net/jfriend00/6m5Kg/

// utility function to set up prototype-based inheritance
// so one object can inherit from another
function inherit(base, derived, methods) {
    derived.prototype = Object.create(base.prototype);
    derived.prototype.constructor = derived;

    for (var name in methods) {
        if (methods.hasOwnProperty(name)) {
            derived.prototype[name] = methods[name];
        }
    }
}

// define base object
function Human(firstName, lastName) {
    // code here to initialize instance data
    this.firstName = firstName;
    this.lastName = lastName;
}

Human.prototype = {
    getName: function() {
        return this.firstName + " " + this.lastName;
    },
    setName: function(firstName, lastName) {
        // set name component if it was passed
        if (firstName) {
            this.firstName = firstName;
        }
        if (lastName) {
            this.lastName = lastName;
        }
    }
}

// define derived object constructor
function European(firstName, lastName, middleName) {
    Human.call(this, firstName, lastName);
    this.middleName = middleName;
}

// inherit from Human object
inherit(Human, European, {
    // override replacement
    getName: function() {
        return this.firstName + " " + this.middleName + " " + this.lastName;
    },
    //override with calling base method - adds one new argument
    setName: function(firstName, lastName, middleName) {
        // call base method
        Human.prototype.setName.call(this, firstName, lastName);
        if (middleName) {
            this.middleName = middleName;
        }
    }
});

This uses Object.create() for assigning to the prototype to avoid any constructor side effects. Object.create() is supported in IE9 and above. If you want to supprt earlier versions of IE, you can use the polyfill for Object.create() here.

share|improve this answer
    
Thanks for your reply. 1. What would be the side effects of new in this case? I think it is rather necessary to use new here to force the parents functions on the child, because they weren't defined in the parents prototype. 2. Your right with the code not running in strict mode but I read one shouldn't use strict mode in the first place so I don't see a Problem here. 3. Multiple Sub-classing levels are no problem. See updated JSFiddle. 5. The second functino name is needed for the this.__super calls to determine the right function on the parent. –  jschwuchow Jul 18 '14 at 9:23
2  
@jschwuchow - I don't know where you read that one shouldn't use strict mode. For me, strict mode prevents a lot of dumb coding mistakes and is very useful with zero downsides (other than preventing bad coding). It is a common mistake when picking up Javascript to try to emulate things in other languages. The prototype inheritance mechanism simply isn't the same as the way Java or C++ does it and to try to treat it that way is a long term mistake. It might feel comfortable if that's what you know, but as I followed that path too initially, I now think that was a mistake. –  jfriend00 Jul 18 '14 at 15:43
    
@jschwuchow - Using new to create an object runs the constructor. Using Object.create(parent.prototype) just copies the prototype without running the constructor. Imagine a constructor that opens a socket or a constructor that registers the new object with some service. You don't want those actions to happen, you just want a copy of the prototype which is what Object.create() does. –  jfriend00 Jul 18 '14 at 15:46
    
@jschwuchow - I updated my comments (based on some of your changes) and added a different example of inheritance. –  jfriend00 Jul 18 '14 at 19:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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