„this“ ist in JavaScript-Klassenmethoden nicht definiert

Lesezeit: 7 Minuten

Ich bin JavaScript-Neuling. Neu, so weit alles, was ich wirklich damit gemacht habe, ist, bestehenden Code zu optimieren und kleine Teile von jQuery zu schreiben.

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, im Request.prototype.start, this ist undefiniert und daher wird die if-Anweisung als falsch ausgewertet. Was mache ich hier falsch?

  • Gibt es einen Grund, den Sie haben start in dem prototype?

    – xj9

    25. Oktober 2010 um 3:56 Uhr

  • Was ist Request.prototype einstellen?

    – Mattball

    25. Oktober 2010 um 3:57 Uhr

  • Ich hatte hier eine ähnliche Frage: stackoverflow.com/questions/3198264/… in der es eine Menge hilfreicher Links gibt. Der springende Punkt ist das this in JavaScript ist nicht ein konstanter Verweis auf den ‘Eigentümer’ einer aufgerufenen prototypischen Funktion, wie es in den meisten OO-Sprachen wie Java der Fall wäre.

    – Marc Bollinger

    25. Oktober 2010 um 4:01 Uhr

  • @Matt: Request ist eine Konstruktorfunktion. Request.prototype ist standardmäßig auf new Object(). Alles, was Sie hinzufügen, wird automatisch zu Eigenschaften von Objekten, die mit erstellt wurden new Request().

    – Chetan S

    25. Oktober 2010 um 4:02 Uhr

  • Ich meine, diese Frage wurde 3 Jahre später als diese gestellt

    – Carson Myers

    8. Mai 2019 um 9:58 Uhr

Ich wollte nur darauf hinweisen, dass dieser Fehler manchmal auftritt, weil eine Funktion als Funktion höherer Ordnung (als Argument übergeben) und dann der Bereich von verwendet wurde this verloren gehen. In solchen Fällen würde ich empfehlen, eine solche Funktion gebunden zu übergeben this. Z.B

this.myFunction.bind(this);

  • Gute Erklärung !! Das war genau das, wonach ich gesucht hatte.

    – vandersondf

    19. Dezember 2019 um 17:12 Uhr

  • Es ist nicht abzusehen, wie viel Kopfschmerzen du mir gerade erspart hast

    – Nativer Codierer

    23. Oktober 2020 um 3:41 Uhr

  • Warum ist der Umfang von this Hau ab?

    – theonlygusti

    12. November 2020 um 14:14 Uhr

  • Gute Frage! Ich hoffe das hilft: eliux.github.io/javascript/common-errors/…

    – Eliux

    28. Januar 2021 um 3:32 Uhr

  • Vielen Dank. Das ist die richtige Antwort! Warum wird das nicht akzeptiert?

    – Benutzer1511417

    15. März 2021 um 12:04 Uhr

Benutzer-Avatar
Chetan S

Wie rufst du die Startfunktion auf?

Das sollte funktionieren (Neu ist der Schlüssel)

var o = new Request(destination, stay_open);
o.start();

Wenn Sie es direkt nennen möchten Request.prototype.start(), this bezieht sich auf den globalen Kontext (window im Browser).

Auch wenn this undefiniert ist, führt dies zu einem Fehler. Der if-Ausdruck wird nicht als falsch ausgewertet.

Aktualisieren: this Das Objekt wird nicht basierend auf der Deklaration festgelegt, sondern von Aufruf. Das bedeutet, wenn Sie die Funktionseigenschaft einer Variablen zuweisen, z x = o.start und Ruf an x(), this inside start bezieht sich nicht mehr auf o. Das passiert, wenn Sie es tun setTimeout. Damit es funktioniert, tun Sie stattdessen Folgendes:

 var o = new Request(...);
 setTimeout(function() { o.start(); }, 1000);

  • Ich verwende setTimeout: var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);

    – Carson Myers

    25. Oktober 2010 um 4:01 Uhr

  • Dies rettete mir das Leben, als ich versuchte zu verstehen, warum die Funktion, die ich zum Ausdruck bringen wollte, basicAuth funktionierte nicht mit der gleichen Ausgabe.

    – Edison Spencer

    22. Mai 2020 um 12:23 Uhr

  • Oder tun o.start.bind(o). Warum nicht x = o.start; x() Arbeit?

    – theonlygusti

    12. November 2020 um 14:14 Uhr

  • .bind() gibt eine neue Funktion zurück, die nicht direkt funktioniert. Also müsstest du tun x = o.start.bind(o); x() oder o.start = o.start.bind(o); x=o.start; x()

    – Zeedob

    7. Dezember 2020 um 13:53 Uhr


Benutzer-Avatar
Nick Greally

Keine der vorherigen Antworten hatte die vollständige Lösung für mich, also poste ich meine hier.

Ich hatte eine Klasse, die beim Ausführen einen Fehler zurückgab forEach auf der Methodenreferenz.

z.B

class Foo {
  hello (name) {
    return `hello ${name}`
  }

  doGreet (name) {
    return console.log(this.hello(name)) // <- 'this' is undefined
  }
}

// print some names...
const foo = new Foo();
(['nick', 'john']).forEach(foo.doGreet)

// TypeError: Cannot read property 'hello' of undefined
//     at doGreet (/.../test.js:7:17)

Die Lösung bestand darin, den Kontext der Methode zu binden this innerhalb eines Konstruktors. dh

class Foo {
  constructor () {
    this.doGreet = this.doGreet.bind(this) // <- Add this
  }

  hello (name) {
    return `hello ${name}`
  }

  doGreet (name) {
    return console.log(this.hello(name))
  }
}

  • PSA: Ich habe versucht, eine Reihe von Verknüpfungen zu erstellen, um dies zu automatisieren oder weniger umständlich zu machen. Leider Object.keys(this) Im Konstruktor konnten nicht alle Schlüssel des Objekts gefunden werden. Das Beste, was ich tun konnte, war dies: const bind = (key) => { this[key] = this[key].bind(this) } Dann ruf an bind('hello'); bind('doGreet') für jeden Methodennamen manuell 🙁

    – Daniel Tonon

    26. Februar um 8:40 Uhr

  • @DanielTonon Siehe meine Antwort 🙂

    – Walter Woschid

    11. Mai um 8:07 Uhr


  • @WalterWoshid schöne Lösung! Werde es mal versuchen.

    – Nick Greally

    11. Mai um 12:34 Uhr

  • Halleluja! Das funktioniert ! Ich danke dir sehr !

    – Bendeg

    8. Juni um 8:31 Uhr

JavaScripts OOP ist ein wenig funky (oder viel) und es ist etwas gewöhnungsbedürftig. Das erste, was Sie beachten müssen, ist das es gibt keine Klassen und das Denken in Klassen kann Sie stolpern lassen. Und um eine an einen Konstruktor (das JavaScript-Äquivalent einer Klassendefinition) angehängte Methode zu verwenden, 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 haben die gleichen Eigenschaften, aber aNinja kann nicht auf die Eigenschaften von zugreifen enemyNinja. (Dieser Teil sollte wirklich einfach/unkompliziert sein) Die Dinge werden etwas anders, wenn Sie anfangen, Dinge zu hinzuzufügen prototype:

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, weil this zeigt nur auf das richtige Objekt (Ihre “Klasse”), wenn der Konstruktor instanziiert wird (andernfalls zeigt er auf das globale Objekt, window im Browser)

In ES2015, auch bekannt als ES6, class ist ein syntaktischer Zucker für functions.

Wenn Sie erzwingen möchten, dass ein Kontext für festgelegt wird this Sie können verwenden bind() Methode. 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 haben wir den Kontext nach innen gezwungen handleChange() zu Form.

  • Sie sollten die Funktion im Konstruktor daran binden. Sonst binden Sie es jedes Mal render wird stattdessen einmal aufgerufen, wenn die Klasse instanziiert wird. Außerdem ist der größte Teil Ihres Beispiels für die Frage nicht wirklich relevant.

    – Eric Haynes

    20. April 2018 um 2:10 Uhr

  • Oder verwenden Sie beim Definieren von die Pfeilsyntax handleChange()

    – Nitin

    24. August 2020 um 22:35 Uhr

Benutzer-Avatar
Kasra

Pfeilfunktion verwenden:

Request.prototype.start = () => {
    if( this.stay_open == true ) {
        this.open({msg: 'listen'});
    } else {

    }
};

  • Sie sollten die Funktion im Konstruktor daran binden. Sonst binden Sie es jedes Mal render wird stattdessen einmal aufgerufen, wenn die Klasse instanziiert wird. Außerdem ist der größte Teil Ihres Beispiels für die Frage nicht wirklich relevant.

    – Eric Haynes

    20. April 2018 um 2:10 Uhr

  • Oder verwenden Sie beim Definieren von die Pfeilsyntax handleChange()

    – Nitin

    24. August 2020 um 22:35 Uhr

Benutzer-Avatar
Oli

Diese Frage wurde beantwortet, aber vielleicht kommt ja noch jemand hierher.

Ich hatte auch ein Problem, wo this ist undefiniert, als ich dummerweise versuchte, die Methoden einer Klasse zu destrukturieren, als ich sie initialisierte:

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

1228230cookie-check„this“ ist in JavaScript-Klassenmethoden nicht definiert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy