Was tun, wenn „dies“ die Kontextverbindung verliert?

Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels „Was tun, wenn„ dies “den Kontext verliert ? Von Cristi Salcescu .

Der beste Weg, um zu vermeiden, dass dieser Kontext verloren geht, besteht darin, ihn nicht zu verwenden. Dies ist jedoch nicht immer möglich. Zum Beispiel arbeiten wir mit dem Code oder der Bibliothek einer anderen Person, die dies verwendet .

Objektliteral, Konstruktorfunktion, Klassenobjektkonstruktor im Prototypsystem. Dieser Pseudoparameter wird im Prototyping-System verwendet, um Zugriff auf die Eigenschaften des Objekts zu erhalten.

Schauen wir uns einige Fälle an.

Verschachtelte Funktionen


Dadurch geht die Kontextreferenz in verschachtelten Funktionen verloren.

class Service { constructor(){ this.numbers = [1,2,3]; this.token = "token"; } doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ //Cannot read property 'forEach' of undefined console.log(number); console.log(this.token); }); }, 100); } } let service = new Service(); service.doSomething(); 

Die Methode doSomething () verfügt über zwei verschachtelte Funktionen: doAnotherthing () und log () . Beim Aufruf von service.doSomething () geht die Kontextreferenz in der verschachtelten Funktion verloren.

bind ()


Eine Möglichkeit, das Problem zu lösen, ist die bind () -Methode. Sehen Sie sich den folgenden Code an:

 doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ console.log(number); console.log(this.token); }.bind(this)); }.bind(this), 100); } 

bind () erstellt eine neue Version der Funktion, die beim Aufruf bereits einen bestimmten Wert davon hat .

Die Funktion doAnotherThing () {/*...*/}.bind(this) erstellt eine Version der Funktion doAnotherThing () , die den Wert von doSomething () übernimmt.

das / selbst


Eine andere Möglichkeit besteht darin, die neue Variable that / self zu deklarieren und zu verwenden, in der dieser Wert aus der Methode doSomething () gespeichert wird.

 doSomething(){ let that = this; setTimeout(function doAnotherThing(){ that.numbers.forEach(function log(number){ console.log(number); console.log(that.token); }); }, 100); } 

Wir müssen let that = this in allen Methoden deklarieren , die dies in verschachtelten Funktionen verwenden.

Pfeilfunktionen


Die Pfeilfunktion gibt uns eine andere Möglichkeit, dieses Problem zu lösen.

 doSomething(){ setTimeout(() => { this.numbers.forEach(number => { console.log(number); console.log(this.token); }); }, 100); } 

Pfeilfunktionen erstellen hierfür keinen eigenen Kontext, sondern verwenden diesen Wert des umgebenden Kontexts. Im obigen Beispiel wird der Wert dieser Funktion der übergeordneten Funktion verwendet.

Der Nachteil dieser Methode ist, dass wir den Namen der Pfeilfunktion nicht angeben können. Der Name der Funktion spielt eine wichtige Rolle, da er die Lesbarkeit des Codes erhöht und seinen Zweck beschreibt.

Unten finden Sie denselben Code mit einer Funktion, die in Form eines Variablennamens ausgedrückt wird:

 doSomething(){ let log = number => { console.log(number); console.log(this.token); } let doAnotherThing = () => { this.numbers.forEach(log); } setTimeout(doAnotherThing, 100); } 

Rückruffunktionen (Methode als Rückruf)


Dies verliert die Kontextreferenz, wenn die Methode als Rückruffunktion verwendet wird. Schauen wir uns die folgende Klasse an:

 class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);//undefined } } let service = new Service(); 

Schauen wir uns Situationen an, in denen die Methode service.doSomething () als Rückruffunktion verwendet wird.

 //callback on DOM event $("#btn").click(service.doSomething); //callback for timer setTimeout(service.doSomething, 0); //callback for custom function run(service.doSomething); function run(fn){ fn(); } 

In allen oben genannten Fällen verliert dies die Kontextverknüpfung.

bind ()


Wir können bind () verwenden , um dieses Problem zu lösen. Unten ist der Code für diese Option:

 //callback on DOM event $("#btn").click(service.doSomething.bind(service)); //callback for timer setTimeout(service.doSomething.bind(service), 0); //callback for custom function run(service.doSomething.bind(service)); 

Pfeilfunktion


Eine andere Möglichkeit besteht darin, eine Pfeilfunktion zu erstellen, die service.doSomething () aufruft.

 //callback on DOM event $("#btn").click(() => service.doSomething()); //callback for timer setTimeout(() => service.doSomething(), 0); //callback for custom function run(() => service.doSomething()); 

Komponenten reagieren


In Komponenten verliert dies die Kontextreferenz, wenn Methoden als Rückrufe für Ereignisse verwendet werden.

 class TodoAddForm extends React.Component { constructor(){ super(); this.todos = []; } componentWillMount() { this.setState({desc: ""}); } add(){ let todo = {desc: this.state.desc}; //Cannot read property 'state' of undefined this.todos.push(todo); } handleChange(event) { //Cannot read property 'setState' of undefined this.setState({desc: event.target.value}); } render() { return <form> <input onChange={this.handleChange} value={this.state.desc} type="text"/> <button onClick={this.add} type="button">Save</button> </form>; } } ReactDOM.render( <TodoAddForm />, document.getElementById('root')); 

Als Lösung können wir im Konstruktor neue Funktionen erstellen, die bind (this) verwenden .

 constructor(){ super(); this.todos = []; this.handleChange = this.handleChange.bind(this); this.add = this.add.bind(this); } 

Verwenden Sie nicht "dies"


Nein das - keine Probleme mit Kontextverlust. Objekte können mit Factory-Funktionen erstellt werden. Schauen Sie sich dieses Beispiel an:

 function Service() { let numbers = [1,2,3]; let token = "token"; function doSomething(){ setTimeout(function doAnotherThing(){ numbers.forEach(function log(number){ console.log(number); console.log(token); }); }, 100); } return Object.freeze({ doSomething }); } 

Der Kontext bleibt erhalten, wenn Sie die Methode als Rückruf verwenden.

 let service = Service(); service.doSomething(); //callback on DOM event $("#btn").click(service.doSomething); //callback for timer setTimeout(service.doSomething, 0); //callback for custom function run(service.doSomething); 

Fazit


Dies verliert in verschiedenen Situationen den Kontextbezug.
bind () , die diese / self- Variablen- und Pfeilfunktionen verwenden, sind Möglichkeiten, Kontextprobleme zu lösen.

Factory-Funktionen ermöglichen das Erstellen von Objekten ohne diese .

Source: https://habr.com/ru/post/de421959/


All Articles