Reputation: 2474
I'd like to have an object with multiple levels of methods and properties. The top level will have properties and methods. Some of these properties will then act as name-spaces for second level methods and properties.
e.g.
//first level methods
base.doStuff();
base.doMore();
//second level methods
base.level2.doStuff();
Doing the first level is straight forward:
function Base(foo) {
this.foo = foo;
}
Base.prototype.doStuff = function () {
console.log(this.foo);
}
Base.prototype.doMore = function () {
console.log(this.foo);
}
base = new Base("bar");
base.doStuff();
Is it possible to get a second level, where in the function expression the "this" keyword points back to the Base constructor?
Upvotes: 0
Views: 142
Reputation: 26183
This is a really bad idea, but here goes:
function Base() {
this.name = 'Base';
this.level2 = new Level2(this);
}
Base.prototype.whatsMyName = function(){
alert(this.name);
};
function Level2(base) {
this.name='Level2';
for(var func in Level2.prototype) {
this[func] = Level2.prototype[func].bind(base);
}
}
Level2.prototype.whatsMyName = function(){
alert(this.name);
};
var b = new Base();
b.whatsMyName(); //Base
b.level2.whatsMyName(); //Also Base
You can see it running here: http://jsfiddle.net/zLFgd/1/
Upvotes: 0
Reputation: 55678
It's much easier to do this without prototypes:
function Base() {
var base = this;
base.level2 = {
moreStuff: function() {
// use "base" instead of "this" here
}
};
}
This can be combined with either prototypical methods, as in your example, or methods defined directly on base
in the constructor. The downside of this is that you are creating the method functions every time you instantiate a new object, so you miss some of the shared-prototype goodness of standard prototypical methods.
You could create a new prototype-based object to be your level2
:
function Level2() {}
Level2.prototype.moreStuff = function() {
// do stuff
}
function Base() {
this.level2 = new Level2();
}
But the methods of base.level2
won't be bound to base
unless you bind them explicitly. Various libraries have bind
support (e.g. Underscore's _.bind
), or you can do it in plain JS:
function Base() {
var base = this;
base.level2 = new Level2();
base.level2.moreStuff = function() {
return Level2.prototype.moreStuff.apply(base, arguments);
}
}
You could further simplify here, but you're always going to have to make new methods bound in one way or another, because JS is never going to assign this
in base.level2.moreStuff()
to base
without explicit binding - so in most cases the first option is the easiest and cleanest.
But really, is it worthwhile just for namespacing? If there's no functional value, it's a lot harder than simply calling your methods level2MoreStuff()
, etc.
Upvotes: 1
Reputation: 3848
Well,
base.doStuff();
is calling doStuff
in context of base
. It is the same as
base.doStuff.call(base);
You can call
and apply
any function, for overriding this
:
var base = new Base();
var someFun = function () {
console.log (this === base); // true
};
someFun.call(base);
Further anonymous example:
var anObj = {
method0: function () {
console.log (this === anObj); // true
}
};
anObj.method1 = function () {
console.log (this === anObj); // true
};
anObj.method0();
anObj.method1();
So the "second level" points this
to level2
, not to the "first level" object.
Upvotes: 0