Ich bin neu in JavaScript. Neu, soweit ich es wirklich getan habe, ist der vorhandene Code optimiert und kleine Teile von jQuery geschrieben.
Jetzt versuche ich, eine "Klasse" mit Attributen und Methoden zu schreiben, aber ich habe Probleme mit den Methoden. Mein Code:
function Request(destination, stay_open) {
this.state = "ready";
this.xhr = null;
this.destination = destination;
this.stay_open = stay_open;
this.open = function(data) {
this.xhr = $.ajax({
url: destination,
success: this.handle_response,
error: this.handle_failure,
timeout: 100000000,
data: data,
dataType: 'json',
});
};
/* snip... */
}
Request.prototype.start = function() {
if( this.stay_open == true ) {
this.open({msg: 'listen'});
} else {
}
};
//all console.log's omitted
Das Problem ist, in Request.prototype.start
, this
ist nicht definiert und damit die if - Anweisung das Ergebnis falsch. Was mache ich hier falsch?
javascript
class
prototype
Carson Myers
quelle
quelle
start
in der habenprototype
?Request.prototype
eingestellt?this
in JavaScript kein ständiger Verweis auf den 'Eigentümer' einer aufgerufenen prototypischen Funktion vorhanden ist, wie dies in den meisten OO-Sprachen wie Java der Fall wäre.new Object()
. Alles, was Sie hinzufügen, wird automatisch zu Eigenschaften von Objekten, die mit erstellt wurdennew Request()
.Request.prototype
ist, wo Instanzen vonRequest
erben. In diesem Fall ist es wahrscheinlichFunction
oderObject
.Antworten:
Wie ruft man die Startfunktion auf?
Dies sollte funktionieren ( neu ist der Schlüssel)
var o = new Request(destination, stay_open); o.start();
Wenn Sie es direkt so nennen
Request.prototype.start()
,this
wird auf den globalen Kontext (window
in Browsern) verwiesen.Wenn dies nicht
this
definiert ist, führt dies zu einem Fehler. Der if-Ausdruck wird nicht als false ausgewertet.Update :
this
Objekt wird nicht basierend auf der Deklaration festgelegt, sondern durch Aufruf . Wenn Sie die Funktionseigenschaft einer Variablen wiex = o.start
und aufrufenx()
,this
bezieht sich dies nicht mehr auf inside starto
. Dies ist, was passiert, wenn Sie dies tunsetTimeout
. Gehen Sie stattdessen folgendermaßen vor, damit es funktioniert:var o = new Request(...); setTimeout(function() { o.start(); }, 1000);
quelle
var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);
o.start.bind(o)
. Warum funktioniert das nichtx = o.start; x()
?.bind()
Gibt eine neue Funktion zurück, die nicht direkt funktioniert. Siex = o.start.bind(o); x()
o.start = o.start.bind(o); x=o.start; x()
Ich wollte nur darauf hinweisen, dass dieser Fehler manchmal auftritt, weil eine Funktion als Funktion höherer Ordnung verwendet wurde (als Argument übergeben) und dann der Umfang von
this
verloren gegangen ist. In solchen Fällen würde ich empfehlen, eine solche Funktion gebunden an zu übergebenthis
. Z.Bthis.myFunction.bind(this);
quelle
this
verloren?JavaScript's OOP ist ein bisschen funky (oder viel) und es ist gewöhnungsbedürftig. Das erste, was Sie beachten müssen, ist das es keine Klassen gibt und das Denken in Klassen Sie stolpern kann. Um eine an einen Konstruktor angehängte Methode zu verwenden (das JavaScript-Äquivalent einer Klassendefinition), müssen Sie Ihr Objekt instanziieren. Zum Beispiel:
Ninja = function (name) { this.name = name; }; aNinja = new Ninja('foxy'); aNinja.name; //-> 'foxy' enemyNinja = new Ninja('boggis'); enemyNinja.name; //=> 'boggis'
Beachten Sie, dass
Ninja
Instanzen dieselben Eigenschaften haben, jedochaNinja
nicht auf die Eigenschaften von zugreifen könnenenemyNinja
. (Dieser Teil sollte wirklich einfach / unkompliziert sein.) Die Dinge werden etwas anders, wenn Sie anfangen, Dinge zu folgenden Elementen hinzuzufügenprototype
:Ninja.prototype.jump = function () { return this.name + ' jumped!'; }; Ninja.prototype.jump(); //-> Error. aNinja.jump(); //-> 'foxy jumped!' enemyNinja.jump(); //-> 'boggis jumped!'
Wenn Sie dies direkt aufrufen, wird ein Fehler ausgegeben, da
this
nur dann auf das richtige Objekt (Ihre "Klasse") verwiesen wird, wenn der Konstruktor instanziiert wird (andernfalls zeigt erwindow
in einem Browser auf das globale Objekt ).quelle
In ES2015 aka ES6
class
ist ein syntaktischer Zucker fürfunctions
.Wenn Sie das Festlegen eines Kontexts erzwingen möchten,
this
können Sie diebind()
Methode verwenden. Wie @chetan betonte, können Sie beim Aufruf auch den Kontext festlegen! Überprüfen Sie das folgende Beispiel:class Form extends React.Component { constructor() { super(); } handleChange(e) { switch (e.target.id) { case 'owner': this.setState({owner: e.target.value}); break; default: } } render() { return ( <form onSubmit={this.handleNewCodeBlock}> <p>Owner:</p> <input onChange={this.handleChange.bind(this)} /> </form> ); } }
Hier wir gezwungen , den Kontext innen
handleChange()
zuForm
.quelle
render
wenn es aufgerufen wird, anstatt einmal, wenn die Klasse instanziiert wird. Außerdem ist der größte Teil Ihres Beispiels für die Frage nicht wirklich relevant.handleChange()
Diese Frage wurde beantwortet, aber vielleicht kommt jemand anderes hierher.
Ich hatte auch ein Problem, bei dem
this
es nicht definiert ist, als ich dummerweise versuchte, die Methoden einer Klasse bei der Initialisierung zu zerstören:import MyClass from "./myClass" // 'this' is not defined here: const { aMethod } = new MyClass() aMethod() // error: 'this' is not defined // So instead, init as you would normally: const myClass = new MyClass() myClass.aMethod() // OK
quelle
Verwenden Sie die Pfeilfunktion:
Request.prototype.start = () => { if( this.stay_open == true ) { this.open({msg: 'listen'}); } else { } };
quelle