Contesto vincolante quando si chiama il metodo ES6. Come accedere all’object dal metodo chiamato callback?

Sto cercando di comprendere la syntax per le classi in ES6. Mentre allo stesso tempo sta imparando il tessuto nativo attraverso il Learning React Native di Bonnie Eisenman.

Sono venuto a conoscenza di un problema relativo all’accesso a this in un callback, quando tale callback è un “metodo” di class. Sono a conoscenza dei problemi relativi a lessicale in callback che sono stati generati molte volte su StackOverflow. Ad esempio in Come accedere al contesto corretto `this` all’interno di un callback? .

Sulla base della mia ricerca online ho trovato una soluzione. Ma non sono sicuro che questo sia il modo corretto di farlo in ES6.

Il mio problema si è verificato quando ho provato quanto segue:

 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 (  ); } } 

(Che ho leggermente modificato dall’esempio nel libro per abbinare la syntax della class ES6 e la syntax di importazione / esportazione invece di Richiedi).

Se faccio questo, this in _handleTextChange non è definito (imansible leggere la proprietà ‘setState’ di undefined). Sono stato sorpreso da questo. Provenendo da altri linguaggi OO, sto interpretando come se questo metodo si comportasse più come se fosse un metodo statico.

Sono stato in grado di risolvere questo problema saltando il metodo di class e utilizzando la notazione a freccia. onSubmitEditing={event => this.setState({name: event.nativeEvent.text})} . Che funziona bene. Non ho problemi o confusione con quello.

Voglio davvero capire come chiamare un metodo di class. Dopo un bel po ‘di ricerche sono riuscito a farlo funzionare come segue: onSubmitEditing={this._handleTextChange.bind(this)} . Forse ho frainteso un aspetto fondamentale di JavaScript (sono un principiante in JS), ma questo mi sembra completamente folle. Non c’è davvero alcun modo di accedere al contesto di un object all’interno di un metodo senza vincolare esplicitamente l’object su … il proprio metodo, nel punto in cui viene chiamato?

Ho anche provato ad aggiungere var self = this; nel costruttore e chiamando self.setState in _handleTextChange . Ma non è stato troppo sorpreso di scoprire che non ha funzionato.

Qual è il modo corretto di accedere a un object da uno dei suoi metodi quando viene chiamato come callback?

Il modo React.createClass (ES5) di creare una class ha una funzione integrata che associa automaticamente tutti i metodi a this . Ma mentre introducevano le classs in ES6 e la migrazione di React.createClass, hanno scoperto che può essere un po ‘di confusione per gli sviluppatori JavaScript che non sono abituati a questa funzione in altre classi, o può confondere quando si spostano da React ad altre classi.

Quindi, decisero di non avere questo built-in nel modello di class di React. Puoi ancora prebindare esplicitamente i metodi nel tuo costruttore, se vuoi

 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}) } 

Ma abbiamo sempre un modo semplice per evitare questo prebinding. Si! Avete capito bene. Funzioni della freccia.

 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 (  ); } } 

A proposito, questo è tutto per quanto riguarda React. La class ES6 ha sempre un modo di accedere al contesto di un object all’interno di un metodo senza vincolare esplicitamente l’object sul proprio metodo.

 class bindTesting { constructor() { this.demo = 'Check 1'; } someMethod() { console.log(this.demo); } callMe() { this.someMethod(); } } let x = new bindTesting(); x.callMe(); //Prints 'Check 1'; 

Ma questo non stampa ‘Check 1’ se lo chiamiamo in JSX Expression.

EDIT :: Come menzionato da @Oka, le funzioni di freccia nei corpi delle classi sono la funzione ES7 + e sono disponibili in Compiler / polyfills come babel. Se non stai usando un transpiler che supporta questa funzione, possiamo semplicemente legarci a this come menzionato sopra o scrivere un nuovo BaseComponent come questo (che è una ctriggers idea)

 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'); } // ... } 

Allontanarsi da ES6 e Reagire per un momento, in un vecchio JavaScript normale, quando si passa il metodo di un object attorno ad esso è solo un riferimento alla funzione stessa, non all’object e alla funzione.

Qualsiasi funzione di invocazione può scegliere di usare l’implicito, chiamando normalmente la funzione, oppure può anche scegliere di cambiare il contesto usando .call e .apply , o .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 

Forse ho frainteso un aspetto fondamentale di JavaScript (sono un principiante in JS), ma questo mi sembra completamente folle. Non c’è davvero alcun modo di accedere al contesto di un object all’interno di un metodo senza vincolare esplicitamente l’object su … il proprio metodo, nel punto in cui viene chiamato?

Bene, i “metodi” non sono di proprietà degli oggetti in javascript. Tutte le funzioni sono valori di prima class (oggetti) e non “parti” di un object o di una class.

L’associazione di this valore avviene quando viene chiamata la funzione, a seconda di come viene chiamata la funzione. Una chiamata di funzione con notazione del metodo ha il suo set sull’object ricevente, una chiamata listener di eventi ha il suo valore impostato sul target di evento corrente e una chiamata di funzione normale ha solo undefined .

Se si accede a un metodo su un’istanza, si tratta in realtà solo dell’accesso alla proprietà di ereditarietà del prototipo standard che produce una funzione, che viene quindi chiamata e associata dynamicmente al destinatario.

Se si desidera chiamare una funzione come metodo su un’istanza quando si tratta di un listener di eventi, è necessario creare in modo esplicito una funzione che esegue questo: il metodo “bound”. In ES6, la notazione a freccia è solitamente preferita per questo.