Question

So I really looked all over the internet and found many different ways on setting prototypal inheritance in javascript.

Some of them use call().
Some of them use this sytnax: var rabbit.prototype = new Animal.
Some of them change the constructor after changing the prototype, some do not.
Some set a little function which helps set inheritance.

Could someone please shed some light on this? There are many posts about this but the good ones are 2+ years old and they've caused a great deal of confusion in my mind.
I would like to know, once and for all, how to actually PROPERLY set prototypal inheritance in javascript.

Even better if it's simple!

Was it helpful?

Solution

Having implemented several different ways of javascript inheritance this is ultimately what I went with when I wanted to construct a javascript game engine for a browser rpg:

The player base class:

function Player(name, type, gender, experience, avatar){
    this.name = name;
    this.type = type;
    this.gender = gender;
    this.experience = experience;
    this.avatar = avatar;

    this.stats ={//getter, setter}
    //lots more code
}

Adding a method to the player class

Player.prototype.decrease_life = function(decrement){} 
//note that the keyword this in the decrease_life function will 
//refer to the player that the method is called on.

Now the inheritance of the player class:

function Mage(name, type, gender, exp, avatar){
    Player.apply(this, [name,type,gender,exp,avatar]); 
    //apply allows you to specify what the keyword 
    //this refers to in the Player super class.
}
Mage.prototype = new Player;

And finally we create a player:

current_player =  new Mage(name,type,gender,0,avatar);

Which allows us to do this now:

current_player.decrease_life(20); //The mage loses 20 life!

Or do this:

current_player.stats.get(); 
//returns the mages stats, it does that because we used apply, and 
//this.stats in the player class is referring to our mage now

As others have mentioned there is no best practice in javascript inheritance. I have found the above most closely imitates how you would expect inheritance to work in Java or C++, which have more typical inheritance structures.

OTHER TIPS

The important thing about prototypal inheritance is that you're inheriting from objects and not classes. So the idea is that tomsBankAccount inherits off bankAccount, which would probably be done via instantation in a class-based language. When you want an 'instance' of a 'class', that'd be done via an object implementing the common features and it being the prototype of any object that wants those features.

Here's a concrete example that is both untested and wrong. But it's wrong for a reason I'll get to.

var bankAccount = {
    withdraw: function(amount) { this.balance -= amount },
    deposit: function(amount) { this.balance += amount }
}

var account1 = {
    balance: 50
}

account1.prototype = bankAccount
account1.deposit(100)
alert(account1.balance)  // Displays 150

So an object has its own stuff like the balance field, yet delegates common functionality off to the bankAccount object. So the equivalent of inheritance would be to decide on a common-case object and prototype from it a lot.

Actually, the above code is broken. JavaScript doesn't let you just prototype off any old object, or at least older JavaScript doesn't. It forces prototyping to be done only from objects that are returned from constructor functions, which have a special syntax in JavaScript when you call them, namely the new keyword.

You may have seen code that looks something like this (again, untested):

function BankAccount(balance) {
    this.balance = balance
    this.withdraw = function(amount) { this.balance -= amount }
    this.deposit = function(amount) { this.balance += amount }
}

var account1 = new BankAccount(50)
account1.deposit(100)
alert(account1.balance)  // Same result as last time

You'll also note they start with a capital letter. That's it, basically. this is odd -- it carries around a reference to the object the function is contained within. So the object carrying the deposit method also carries around the balance attribute, which is why we can access balance via this from the methods.

But the above code isn't idiomatic JavaScript. There are things to remember once you've got the hang of it. For example, the above reassigns new methods on every object construction which is obviously not quick. This is resolved by assigning methods to a function constructor's prototype. There's also the ability to 'privatise' attributes via JavaScript's closures.

You may suspect that JavaScript's Java-like notation for doing objects is completely misleading given that its so different underneath... and I'd agree.

There is no truly uniform 'best way' to do it. 'Good answers' from 2 years old are still relevant (if they are good that is and I personally would discard anything that tries to emulate a class), since javascript (EcmaScript) is quite old (over a decade).

call is used to pass what this is.

As to prototypal inheritance: I really liked 'crockford on javascript' from the YUI Theater. You'd want to watch 'Act III: function the ultimate'

The simplest way to set the prototype is:
objectIdentifier.prototype.methodIdentifier = function(args){ /* your code*/ }

There are many different 'construct-patterns' and most of them have their use in a specific given situation. It is generally a good idea to think about what a piece of code is going to do and how often you use it. You'd also want to look at some popular library's like JQuery and look at their patterns.

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top