9 Stimmen

Wie kann man eine Prototyp-Funktion übergeben?

Ich bin ein Neuling in Sachen Javascript und brauche etwas Hilfe. Ich habe versucht, Radius durch Funktion zu summieren, aber bekam einen undefinierten Fehler:(

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, number);
}

function addFivetoIt(func) {
    func(5);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy);

27voto

zetlen Punkte 3569

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)

0voto

vkarpov15 Punkte 3089

Das Tückische an this in JavaScript ist, dass sie das Objekt enthält, von dem die Funktion eine Eigenschaft war als es noch hieß standardmäßig. Wenn Sie also MyCircle.increaseRadiusBy als Parameter, rufen Sie es dann als func() Die Funktion ist also keine Eigenschaft eines beliebigen Objekts. Der einfachste Weg, die Funktion this ist die Verwendung des call() Funktion:

function addFivetoIt(func, context) {
    // The first parameter to `call()` is the value of `this` in the function
    func.call(context, 5);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, MyCircle);

Der nachstehende Ansatz, bei dem func als Eigenschaft, bevor sie aufgerufen wird, funktioniert ebenfalls. In der Praxis würde man das nie tun, weil es eine unnötige Eigenschaft zu context aber es ist ein gutes didaktisches Beispiel, um zu zeigen, wie this funktioniert.

function addFivetoIt(func, context) {
    context.func = func;
    context.func(5);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, MyCircle);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X