ماذا تفعل عندما يفقد "هذا" ارتباط السياق

مرحبا يا هبر! أقدم لكم ترجمة المقال "ماذا أفعل عندما يفقد هذا" السياق " بقلم كريستي سالسيسكو .

أفضل طريقة لتجنب فقدان هذا السياق هي عدم استخدام هذا . ومع ذلك ، هذا ليس ممكنًا دائمًا. على سبيل المثال ، نحن نعمل مع كود أو مكتبة شخص آخر يستخدم هذا .

حرفية الكائن ، وظيفة المُنشئ ، مُنشئ كائن الفئة في نظام النموذج الأولي. يتم استخدام هذه المعلمة الزائفة في نظام النماذج الأولية من أجل الوصول إلى خصائص الكائن.

دعونا نلقي نظرة على بعض الحالات.

دالات متداخلة


هذا يفقد مرجع السياق داخل الدالات المتداخلة.

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

يحتوي أسلوب doSomething () على دالتين متداخلتين: doAnotherthing () و log () . عند استدعاء service.doSomething () ، يفقد هذا مرجع السياق في الدالة المتداخلة.

ربط ()


طريقة واحدة لحل المشكلة باستخدام طريقة bind () . ألق نظرة على الكود التالي:

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

يقوم bind () بإنشاء نسخة جديدة من الدالة ، والتي عند استدعاء لها بالفعل قيمة معينة من هذا .

دالة doAnotherThing () {/*...//..bind(this) تنشئ نسخة من وظيفة doAnotherThing () ، والتي تأخذ قيمة هذا من doSomething () .

هذا / النفس


خيار آخر هو إعلان واستخدام المتغير / self الجديد ، الذي سيخزن هذه القيمة من طريقة doSomething () .

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

يجب أن نعلن أن ندع ذلك = في جميع الطرق باستخدام هذا في الوظائف المتداخلة.

وظائف السهم


تعطينا وظيفة السهم طريقة أخرى لحل هذه المشكلة.

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

لا تقوم دالات السهم بإنشاء السياق الخاص بها لهذا ، بل تستخدم هذه القيمة للسياق المحيط. في المثال أعلاه ، يستخدم قيمة هذه الوظيفة الأصل.

عيب هذه الطريقة هو أنه لا يمكننا تحديد اسم وظيفة السهم. يلعب اسم الوظيفة دورًا مهمًا ، لأنه يزيد من سهولة قراءة الشفرة ويصف الغرض منها.

يوجد أدناه نفس الرمز مع دالة تم التعبير عنها من حيث اسم متغير:

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

وظائف رد الاتصال (طريقة رد الاتصال)


هذا يفقد مرجع السياق عند استخدام الأسلوب كدالة رد اتصال. دعونا نلقي نظرة على الفصل التالي:

 class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);//undefined } } let service = new 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); function run(fn){ fn(); } 

في جميع الحالات أعلاه ، يفقد هذا ارتباط السياق.

ربط ()


يمكننا استخدام bind () لحل هذه المشكلة. يوجد أدناه رمز هذا الخيار:

 //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)); 

وظيفة السهم


طريقة أخرى هي إنشاء وظيفة سهم تستدعي service.doSomething () .

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

مكونات التفاعل


في المكونات ، يفقد هذا مرجع السياق عند استخدام الطرق كرد اتصال للأحداث.

 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')); 

كحل ، يمكننا إنشاء وظائف جديدة في المُنشئ الذي سيستخدم الربط (هذا) .

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

لا تستخدم "هذا"


لا هذا - لا مشاكل مع فقدان السياق. يمكن إنشاء الكائنات باستخدام وظائف المصنع . نلقي نظرة على هذا المثال:

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

يبقى السياق إذا كنت تستخدم الأسلوب كرد اتصال.

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

الخلاصة


هذا يفقد مرجع السياق في حالات مختلفة.
bind () ، استخدام هذا المتغير / الدوال ذات السهم والسهم هي طرق لحل مشاكل السياق.

تتيح وظائف المصنع إمكانية إنشاء كائنات دون استخدام ذلك .

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


All Articles