Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extends a javascript object?

Tags:

javascript

I made a simple example of my problem with a babel object :

function babel(){
    this.english = {
        hello: function () { alert('hello'); },
        goodbye: function () { alert('goodbye'); }
        teeshirt: function () { alert('T-shirt'); }
    }
}

Now, I want to extends this object :

babel.prototype.french = {
    bonjour: function () { alert('bonjour'); },
    aurevoir: function () { alert('au revoir'); }
}

But what if I need to use an existing function define before ?

babel.prototype.french = {
    bonjour: function () { alert('bonjour'); },
    aurevoir: function () { alert('aurevoir'); },
    teeshirt: function () { this.english.teeshirt(); }
}

What I could do is :

var say = new babel();

(function (_this) {
    babel.prototype.french = {
    bonjour: function () { alert('bonjour'); },
    aurevoir: function () { alert('aurevoir'); },
    hello: function () { _this.english.hello(); }
    }
})(say);

But in this case, I will always use the context of the say object, isn't it ?

like image 627
Natim Avatar asked Dec 04 '11 07:12

Natim


2 Answers

The problem is, that in teeshirt function call this points to the french object, not babel object. If you have to access parent object, you should store reference to it somewhere. For example you can change your constructor like this:

function babel(){
    this.english = {
        parent: this,
        hello: function () { alert('hello'); },
        goodbye: function () { alert('goodbye'); }
        teeshirt: function () { this.parent.french.something(); }
    }
}

But as you can see, there is a problem if you don't create object in constructor. I don't see any 'nice' approach, but you can do this:

function babel(){
    this.english = {
        parent: this,
        hello: function () { alert('hello'); },
        goodbye: function () { alert('goodbye'); }
        teeshirt: function () { this.parent.french.something(); }
    };
    for (var i in babel.prototype) {
        this[i].parent = this;
    }
}

Then your french will look like this:

babel.prototype.french = {
    bonjour: function () { alert('bonjour'); },
    aurevoir: function () { alert('aurevoir'); },
    teeshirt: function () { this.parent.english.teeshirt(); }
}
like image 51
Krzysztof Avatar answered Sep 21 '22 04:09

Krzysztof


While the question as asked does bring up all the fascinating issues with JavaScript's this and prototypal inheritance, I would suggest simplifying the whole problem and refactoring your objects. There are a couple ways to do this.

If the English version of teeshirt is the default, it should be in the object which is at the end of the prototype chain. That is, a French object would have as its prototype an English object. The French object would simply not contain a teeshirt member. This is similar to the way resource bundles work.

Now this idea may not work for you, because the relationship among the different bundles may be complex: perhaps sometimes Engish is a fallback sometimes but not other times. In this case, see if you can make your babel objects all singletons (i.e., just plain objects).

var babel = {}

babel.english = {
    hello: function () { alert('hello'); },
    goodbye: function () { alert('goodbye'); },
    teeshirt: function () { alert('T-shirt'); }
}

babel.french = {
    bonjour: function () { alert('bonjour'); },
    aurevoir: function () { alert('aurevoir'); },
    teeshirt: function () { babel.english.teeshirt(); }
}

babel.english.teeshirt();
babel.french.teeshirt();

Try it at http://jsfiddle.net/yRnLj/

I realize this looks like a complete avoidance of your interesting question. But if you only need one copy of each language bundle, it is a lot simpler. :-)

like image 20
Ray Toal Avatar answered Sep 23 '22 04:09

Ray Toal