Sorry if it's hard to explain. Suppose class Y extends class Z, and class X extends class Y
The thing is if a class doesn't have a method, it calls it's super class, so far so good.
X.prototype.v = function{return this.getV();} //getV() doesn't exist in class X
since class X extends class Y and getV() exist in class Y, the call goes here:
Y.prototype.getV = function{return this.parent().getV()+1}
the working function parent() returns an instance of it's super class. Suppose z also has a method getV, which returns a real int value.
Z.prototype.getV = function{return 1}
So the function getV() in class Y is mean to return the getV value from Z plus 1, and send it to the lowest class X.
Most wired part is here. As long as the method getV is called from X.v(), 'this' in y.getV() refer to X, not Y!
so the function getV() in Y becomes X.parent().getV()+1, and I get 'maximum call stack size exceeded'
A stupid but extremely effective way to solve this, is to write
this.parent().parent().getV()+1
double parents make the sender Z not y, then it returns 2 when calling X.getV()
It's stupid because if the caller is Y itself, like Y.getV(), I think then 'this' correctly means Y here, then there're too many parent() calls, leading it to undefined.
Some thoughts like we can get rid of 'this', and use another way to get current class. Less desirable way might be keeping track of all functions for all classes, and set the correct number of parent(). I believe there's more. However, none of them was tested out yet.
A minimal code example, taken from the pieces of code above, can be:
class Z{
}
class Y extends Z{
}
class X extends Y{
}
X.prototype.v = function{
return this.getV();
}
Y.prototype.getV = function{
return this.parent().getV()+1;
}
Z.prototype.getV = function{
return 1;
}
var x = new X();
console.log(x.v());
this
refers to the context in which a function is called, or in more practical terms: it refers to the object that appears before the dot in the call. When you call abc.def()
, then this
in def
will be the same as abc
.
So the easiest might be to change this:
X.prototype.v = function{return this.getV();}
to:
X.prototype.v = function{return this.parent().getV();}
This makes the this
for Y to be the above this.parent()
. This way you don't have to change your original call.
But if you want to keep the flexibility to define X.prototype.getV, then it is probably better to define it immediately, and instead of the above change, do this:
X.prototype.v = function{return this.getV();}
X.prototype.getV = function{return this.parent().getV();}
You could pass an explicit reference to what the target function should use as this
, using the apply
method (or call
which is anther flavour of the same):
X.prototype.v = function{return this.getV.apply(this.parent(), arguments);}
You could use hasOwnProperty
:
X.prototype.v = function{
var nextThis = X.prototype.hasOwnProperty('getV') ? this : this.parent();
return this.getV.apply(nextThis, arguments);
}
`