Das Problem besteht darin, dass Sie einer Funktion einen Verweis auf eine andere Funktion übergeben und die übergebene Funktion daher ihren Geltungsbereich verliert! Hier ist die beanstandete Zeile:
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, number);
}
JavaScript-Objekte sind in mancher Hinsicht einfacher, als sie erscheinen. Als Sie die getRadius
Methode zum Circle
Prototyp haben Sie keine Klassenmethode definiert, wie es in der klassischen OO üblich ist. Sie haben einfach eine benannte Eigenschaft des Prototyps definiert und dem Wert dieser Eigenschaft eine Funktion zugewiesen. Wenn Sie this.getRadius
als Argument für eine statische Funktion, wie sumWithFunction
den Kontext von this
ist verloren. Es wird mit dem this
Schlüsselwort gebunden an window
und da window
hat keine r
Eigenschaft, gibt der Browser einen undefinierten Fehler aus.
Mit anderen Worten, die Erklärung this.getRadius()
bedeutet eigentlich "führe die Funktion aus, die dem getRadius
Eigenschaft von this
und führen Sie es in der Kontext de this
. Wenn die Funktion nicht explizit über diese Anweisung aufgerufen wird, wird der Kontext nicht zugewiesen.
Eine gängige Lösung für dieses Problem besteht darin, jeder Funktion, die eine andere Funktion empfängt, ein erwartetes Argument für den Kontext hinzuzufügen.
function sumWithFunction(func, context, number) {
return func.apply(context) + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, this, number);
}
function addFivetoIt(func, context) {
func.apply(context,[5]);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, myCircle);
Eine einfachere, aber weniger robuste Lösung wäre es, eine Funktion inline zu deklarieren, die auf eine Kontextreferenz in der lokalen Schließung zugreifen kann.
function sumWithFunction(func, number) {
return func() + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
var me = this;
this.r = sumWithFunction(function() {
return me.getRadius()
}, number);
}
function addFivetoIt(func) {
func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(function(number) {
return MyCircle.increaseRadiusBy(number);
});
Die bei weitem einfachste Lösung ist jedoch die Verwendung eines neueren Features von ECMAScript, einer Funktionsmethode namens bind
. Hier wird es gut erklärt einschließlich der Tatsache, dass es nicht von allen Browsern unterstützt wird. Aus diesem Grund haben viele Bibliotheken wie jQuery, Prototype usw. browserübergreifende Methoden zur Funktionsbindung wie $.proxy
.
function sumWithFunction(func, number) {
return func() + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius.bind(this), number); // or $.proxy(this.getRadius,this)
}
function addFivetoIt(func) {
func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy.bind(MyCircle)); // or $.proxy(MyCircle.increaseRadiusBy,MyCircle)