2016-02-21 5 views
12

Ich versuche, mich um die Syntax für Klassen in ES6 zu wickeln. Während gleichzeitig lernen Fabric native durch Bonnie Eisenmans Learning React Native.Bindungskontext beim Aufruf der ES6-Methode. Wie kann man auf ein Objekt innerhalb einer als Callback bezeichneten Methode zugreifen?

Ich bin über ein Problem beim Zugriff auf this in einem Rückruf gekommen, wenn dieser Rückruf eine Klasse "Methode" ist. Ich bin mir bewusst, Probleme um lexikalische this in Rückrufe wurden oft auf StackOverflow ausgelöst. Zum Beispiel in How to access the correct `this` context inside a callback?.

Basierend auf meinen Recherchen online bin ich auf eine Lösung gestoßen. Aber ich bin mir nicht sicher, ob das in ES6 der richtige Weg ist.

Mein Problem entstand, als ich versuchte, die folgenden unten:

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     zip: '' 
    }; 
    } 

    _handleTextChange(event) { 
    console.log(event.nativeEvent.text); 
    this.setState({zip: event.nativeEvent.text}) 
    } 

    render() { 
    return (
     <TextInput 
     style={styles.input} 
     onSubmitEditing={this._handleTextChange}/> 
    ); 
    } 
} 

(Was ich habe nur etwas aus dem Beispiel in dem Buch modifiziert, um die ES6 Klasse Syntax entsprechen und die Import/Export-Syntax statt Require.)

Wenn ich dies tue, ist die this in _handleTextChange nicht definiert (Eigenschaft 'setState' von undefined kann nicht gelesen werden). Ich war davon überrascht. Aus anderen OO-Sprachen kommend, interpretiere ich, als ob diese Methode sich mehr wie eine statische Methode verhält.

Ich konnte dies lösen, indem ich die Klassenmethode überspringe und die Pfeilnotation verwende. onSubmitEditing={event => this.setState({name: event.nativeEvent.text})}. Was gut funktioniert. Ich habe keine Probleme oder Verwirrung damit.

Ich möchte wirklich herausfinden, wie eine Klassenmethode aufgerufen wird. Nach ein wenig Forschung habe ich es geschafft, es zu tun, indem ich Folgendes mache: onSubmitEditing={this._handleTextChange.bind(this)}. Vielleicht habe ich einen grundlegenden Aspekt von JavaScript missverstanden (ich bin ein Anfänger in JS), aber das scheint mir völlig verrückt zu sein. Gibt es wirklich keine Möglichkeit, von einer Methode aus auf den Kontext eines Objekts zuzugreifen, ohne das Objekt explizit an ... seine eigene Methode an dem Punkt zu binden, an dem es aufgerufen wird?

Ich habe auch versucht, var self = this; im Konstruktor und Aufruf self.setState in _handleTextChange. Aber war nicht zu überrascht zu finden, dass das nicht funktioniert hat.

Was ist der richtige Weg für den Zugriff auf ein Objekt aus einer seiner Methoden, wenn es als Callback aufgerufen wird?

+0

Alle möglichen Möglichkeiten sind in der Frage beschrieben, die Sie verknüpft haben. Man könnte argumentieren, dass der richtigste derjenige ist, der deine Absichten am deutlichsten zum Ausdruck bringt. –

Antwort

13

Die Methode React.createClass (ES5) zum Erstellen einer Klasse verfügt über eine integrierte Funktion, die alle Methoden automatisch an this bindet. Bei der Einführung von classes in ES6 und der Migration von React.createClass fanden sie heraus, dass es für JavaScript-Entwickler, die in anderen Klassen nicht an diese Funktion gewöhnt sind, etwas verwirrend sein kann, oder wenn sie von React in andere Klassen wechseln.

Also beschlossen sie, dies nicht in Reacts Klassenmodell eingebaut zu haben. Sie können immer noch explizit Prebind Methoden in Ihrem Konstruktor, wenn Sie wollen, wie

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     zip: '' 
    }; 
    this._handleTextChange = this._handleTextChange.bind(this); //Binding to `this` 
    } 

    _handleTextChange(event) { 
    console.log(event.nativeEvent.text); 
    this.setState({zip: event.nativeEvent.text}) 
    } 

Aber wir haben immer eine einfache Möglichkeit, diese Prebinding zu vermeiden. Ja! Du hast es. Pfeilfunktionen

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     zip: '' 
    }; 
    } 

    _handleTextChange = event => { 
    console.log(event.nativeEvent.text); 
    this.setState({zip: event.nativeEvent.text}) 
    } 

    render() { 
    return (
     <TextInput 
     style={styles.input} 
     onSubmitEditing={this._handleTextChange}/> 
    ); 
    } 
} 

Übrigens, das ist alles in Bezug auf React. Die ES6-Klasse hat immer eine Möglichkeit, von einer Methode aus auf den Kontext eines Objekts zuzugreifen, ohne das Objekt explizit an die eigene Methode zu binden.

class bindTesting { 
    constructor() { 
    this.demo = 'Check 1'; 
    } 

    someMethod() { 
    console.log(this.demo); 
    } 

    callMe() { 
    this.someMethod(); 
    } 
} 

let x = new bindTesting(); 
x.callMe(); //Prints 'Check 1'; 

Aber das druckt 'Check 1' nicht, wenn wir es in JSX Expression aufrufen.

EDIT :: Wie @Oka erwähnt, Pfeilfunktionen in Klassenkörpern ist ES7 + -Funktion und in Compiler/Polyfills wie Babel verfügbar. Wenn Sie nicht Transpiler verwenden, die diese Funktion unterstützen, können wir binden nur an this wie oben erwähnt, oder einen neuen BaseComponent so schreiben (was eine schlechte Idee ist)

class BaseComponent extends React.Component { 
_bind(...methods) { 
    methods.forEach((method) => this[method] = this[method].bind(this)); 
} 
} 

class ExampleComponent extends BaseComponent { 
constructor() { 
    super(); 
    this._bind('_handleTextChange', '_handleClick'); 
} 
// ... 
} 
+2

Arrow-Funktionen in 'class'-Körpern sind ein ES7-Vorschlag und werden in Transfilern wie Babel als experimentell betrachtet. – Oka

+0

@Oka Ja! True – Prasanth

+0

@gunshot Das Ändern der Variablen, um auf die Methode innerhalb des Konstruktors zuzugreifen, um eine Version mit korrekt gebundenem Objektkontext zu sein, ist genau die Art von Lösung, nach der ich gesucht habe, aber für mich selbst nicht funktionieren konnte. Vielen Dank. Ich werde '' 'this._handleTextChange = this._handleTextChange.bind (this); '' '. Genial! – rod

6

von ES6 Ausbrechen und Reagieren für Ein Moment, in normalem altem JavaScript, wenn Sie die Methode eines Objekts umgehen, ist es nur ein Verweis auf die Funktion selbst, nicht das Objekt und die Funktion.

Jede Funktion kann wählen rufenden die implizite this verwenden, indem die Funktion normalerweise aufrufen, oder es kann sogar wählen, um den Kontext zu ändern .call und .apply, oder .bind.

var O = { 
 
    foo: function() { 
 
    console.log(this); 
 
    }, 
 
    bar: 51 
 
}; 
 

 
O.foo(); // `this` is O, the implicit context, inferred from the object host 
 

 
var foo = O.foo; 
 

 
foo(); // `this` is is the global object, or undefined in Strict Mode

Was geschieht, ist, sind vorbei Sie die _handleTextChangeFunktion zu einem Ereignis-Emitter, der einige Zeit später ausgeführt wird. Der Event-Emitter hat keine Ahnung, dass er die Funktion Methode erhalten hat. Es führt es nur aus.

var O = { 
 
    foo: function (event) { 
 
    console.log(this); 
 
    console.log(event); 
 
    }, 
 
    bar: 51 
 
}; 
 

 
function invoke (func) { // the function reference held by O.foo is now held by `func` 
 
    func('some param'); // it has no idea as to what the contextual `this` is bound to, maybe its implicitly global, maybe its explicitly bound, maybe its undefined 
 
} 
 

 
invoke(O.foo); 
 

 
invoke(O.foo.bind(O)); // A copy of the function with the context explicitly bound

einen Blick auf Kontext-Sharing Nehmen:

function foo() { 
 
    console.log(this.a); 
 
} 
 

 
// Both object hold references to the foo function 
 
var O = { foo : foo, a : 5 }, 
 
    O2 = { bar : foo, a : 1 }; 
 

 
O.foo(); // implicit `this` from O 
 
O2.bar(); // implicit `this` from O2 
 

 
var Z = { a : 23 }; 
 

 
O.foo.call(Z); // explicit `this` from Z

Sie beliebig mit diesen Beispielen kompliziert werden kann.

3

Vielleicht habe ich einen grundlegenden Aspekt von JavaScript missverstanden (ich bin ein Anfänger in JS), aber das scheint völlig verrückt nach mir. Gibt es wirklich keine Möglichkeit, von einer Methode aus auf den Kontext eines Objekts zuzugreifen, ohne das Objekt explizit an ... seine eigene Methode an dem Punkt zu binden, an dem es aufgerufen wird?

Nun, "Methoden" sind nicht von Objekten in JavaScript gehört. Alle Funktionen sind erstklassige Werte (Objekte) und nicht "Teile" eines Objekts oder einer Klasse.

Die Bindung des this value passiert, wenn die Funktion aufgerufen wird, abhängig davon, wie die Funktion aufgerufen wird. Ein Funktionsaufruf mit Methodenschreibweise hat this auf das empfangende Objekt festgelegt, ein Ereignislisteneraufruf hat this auf das aktuelle Ereignisziel festgelegt, und ein normaler Funktionsaufruf hat nur undefined.

Wenn Sie auf eine Methode für eine Instanz zugreifen, handelt es sich tatsächlich nur um den Standard-Zugriff auf die Prototyp-Vererbung, der eine Funktion ergibt, die dann aufgerufen und dynamisch an den Empfänger gebunden wird.

Wenn Sie eine Funktion als Methode für eine Instanz aufrufen möchten, wenn es sich um einen Ereignis-Listener handelt, müssen Sie explizit eine Funktion erstellen, die dies tut - die "gebundene" Methode. In ES6 wird dafür normalerweise die Pfeilnotation bevorzugt.

Verwandte Themen