จะเข้าถึง "this" ที่ถูกต้องภายในการโทรกลับได้อย่างไร
ฉันมีฟังก์ชันตัวสร้างที่ลงทะเบียนตัวจัดการเหตุการณ์:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
อย่างไรก็ตามฉันไม่สามารถเข้าถึงdata
คุณสมบัติของวัตถุที่สร้างขึ้นภายในการเรียกกลับ ดูเหมือนว่าthis
จะไม่ได้อ้างถึงออบเจ็กต์ที่ถูกสร้างขึ้น แต่เป็นอีกชิ้นหนึ่ง
ฉันยังพยายามใช้วิธีการวัตถุแทนฟังก์ชันที่ไม่ระบุชื่อ:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
แต่มันแสดงปัญหาเดียวกัน
ฉันจะเข้าถึงวัตถุที่ถูกต้องได้อย่างไร?
คำตอบ
สิ่งที่คุณควรรู้ this
this
(aka "the context") เป็นคีย์เวิร์ดพิเศษภายในแต่ละฟังก์ชันและค่าของมันขึ้นอยู่กับวิธีการเรียกใช้ฟังก์ชันเท่านั้นไม่ใช่ว่ากำหนดอย่างไร / เมื่อใด / ที่ใด ไม่ได้รับผลกระทบจากขอบเขตคำศัพท์เหมือนตัวแปรอื่น ๆ (ยกเว้นฟังก์ชันลูกศรดูด้านล่าง) นี่คือตัวอย่างบางส่วน:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการthis
มีลักษณะที่เป็นเอกสาร MDN
วิธีการอ้างอิงที่ถูกต้อง this
ใช้ฟังก์ชันลูกศร
ECMAScript 6 แนะนำฟังก์ชันลูกศรซึ่งสามารถคิดได้ว่าเป็นฟังก์ชันแลมบ์ดา พวกเขาไม่มีthis
ผลผูกพันของตัวเอง แต่this
จะถูกค้นหาในขอบเขตเช่นเดียวกับตัวแปรปกติ .bind
นั่นหมายความว่าคุณจะได้ไม่ต้องโทร นั่นไม่ใช่พฤติกรรมพิเศษเพียงอย่างเดียวที่พวกเขามีโปรดดูเอกสาร MDN สำหรับข้อมูลเพิ่มเติม
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
อย่าใช้ this
จริงๆคุณไม่ต้องการที่จะเข้าถึงthis
โดยเฉพาะอย่างยิ่ง แต่วัตถุที่มันหมายถึง นั่นเป็นเหตุผลที่วิธีแก้ปัญหาง่ายๆคือสร้างตัวแปรใหม่ที่อ้างถึงวัตถุนั้นด้วย ตัวแปรสามารถมีชื่อใด ๆ แต่คนทั่วไปและself
that
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
เนื่องจากself
เป็นตัวแปรปกติจึงปฏิบัติตามกฎขอบเขตศัพท์และสามารถเข้าถึงได้ภายในการเรียกกลับ นอกจากนี้ยังมีข้อดีที่คุณสามารถเข้าถึงthis
มูลค่าของการโทรกลับได้
การตั้งค่าthis
การโทรกลับอย่างชัดเจน- ตอนที่ 1
อาจดูเหมือนว่าคุณไม่สามารถควบคุมค่าได้this
เนื่องจากค่าของมันถูกตั้งค่าโดยอัตโนมัติ แต่จริงๆแล้วไม่เป็นเช่นนั้น
ทุกฟังก์ชันมี method .bind
[docs]ซึ่งจะส่งคืนฟังก์ชันใหม่โดยthis
ผูกไว้กับค่า ฟังก์ชันนี้มีลักษณะการทำงานเหมือนกับที่คุณเรียก.bind
ใช้เฉพาะที่this
คุณกำหนดไว้เท่านั้น ไม่ว่าฟังก์ชันนั้นจะถูกเรียกใช้อย่างไรหรือเมื่อใดก็ตามthis
จะอ้างถึงค่าที่ผ่านเสมอ
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
ในกรณีนี้เราจะมีผลผูกพันการเรียกกลับของthis
ค่าของ'sMyConstructor
this
หมายเหตุ:เมื่อบริบทที่มีผลผูกพันสำหรับ jQuery ให้ใช้jQuery.proxy
[docs]แทน เหตุผลในการทำเช่นนี้คือคุณไม่จำเป็นต้องจัดเก็บข้อมูลอ้างอิงของฟังก์ชันเมื่อยกเลิกการผูกการเรียกกลับเหตุการณ์ jQuery จัดการสิ่งนั้นภายใน
ชุดthis
การโทรกลับ - ตอนที่ 2
ฟังก์ชัน / วิธีการบางอย่างที่ยอมรับการโทรกลับยังยอมรับค่าที่การเรียกกลับthis
ควรอ้างถึง โดยพื้นฐานแล้วจะเหมือนกับการผูกมัดตัวเอง แต่ฟังก์ชัน / วิธีการนี้จะทำเพื่อคุณ Array#map
[docs]เป็นวิธีการดังกล่าว ลายเซ็นคือ:
array.map(callback[, thisArg])
อาร์กิวเมนต์แรกคือการเรียกกลับและอาร์กิวเมนต์ที่สองคือค่าที่this
ควรอ้างถึง นี่คือตัวอย่างที่สร้างขึ้น:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
หมายเหตุ:คุณสามารถส่งค่าสำหรับได้หรือไม่this
โดยปกติจะกล่าวถึงในเอกสารของฟังก์ชัน / วิธีการนั้น ตัวอย่างเช่นวิธีการของ jQuery [เอกสาร]$.ajax
อธิบายตัวเลือกที่เรียกว่าcontext
:
วัตถุนี้จะสร้างบริบทของการเรียกกลับที่เกี่ยวข้องกับ Ajax ทั้งหมด
ปัญหาทั่วไป: การใช้เมธอดอ็อบเจ็กต์เป็น callbacks / event handlers
อาการทั่วไปอีกประการหนึ่งของปัญหานี้คือเมื่อใช้เมธอดอ็อบเจ็กต์เป็นตัวจัดการการเรียกกลับ / เหตุการณ์ ฟังก์ชันเป็นพลเมืองชั้นหนึ่งใน JavaScript และคำว่า "วิธีการ" เป็นเพียงคำเรียกขานสำหรับฟังก์ชันที่เป็นค่าของคุณสมบัติวัตถุ แต่ฟังก์ชันนั้นไม่มีลิงก์เฉพาะไปยังวัตถุ "ที่มี" ของมัน
พิจารณาตัวอย่างต่อไปนี้:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
ฟังก์ชั่นthis.method
ที่ได้รับมอบหมายเป็นตัวจัดการเหตุการณ์ค แต่ถ้าdocument.body
มีการคลิกค่าลงทะเบียนจะเป็นundefined
เพราะภายในตัวจัดการเหตุการณ์ที่this
หมายถึงไม่ได้ตัวอย่างของdocument.body
ดังกล่าวแล้วที่จุดเริ่มต้นสิ่งที่หมายถึงขึ้นอยู่กับวิธีการทำงานจะเรียกว่าไม่ว่ามันถูกกำหนดไว้
หากรหัสเป็นดังต่อไปนี้อาจเห็นได้ชัดว่าฟังก์ชันไม่มีการอ้างอิงโดยนัยถึงวัตถุ:Foo
this
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
วิธีแก้ปัญหาเหมือนกับที่กล่าวไว้ข้างต้น: หากมีให้ใช้.bind
เพื่อผูกthis
กับค่าเฉพาะอย่างชัดเจน
document.body.onclick = this.method.bind(this);
หรือเรียกฟังก์ชันอย่างชัดเจนว่าเป็น "วิธีการ" ของวัตถุโดยใช้ฟังก์ชันที่ไม่ระบุชื่อเป็นตัวจัดการการเรียกกลับ / เหตุการณ์และกำหนดวัตถุ ( this
) ให้กับตัวแปรอื่น:
var self = this;
document.body.onclick = function() {
self.method();
};
หรือใช้ฟังก์ชันลูกศร:
document.body.onclick = () => this.method();
มีหลายวิธีในการเข้าถึงบริบทหลักในบริบทลูก -
- คุณสามารถใช้
bind()
ฟังก์ชัน - จัดเก็บการอ้างอิงบริบท / สิ่งนี้ภายในตัวแปรอื่น (ดูตัวอย่างด้านล่าง)
- ใช้ฟังก์ชันES6 Arrow
- แก้ไขโค้ด / การออกแบบฟังก์ชัน / สถาปัตยกรรม - สำหรับสิ่งนี้คุณควรมีคำสั่งเกี่ยวกับ รูปแบบการออกแบบในจาวาสคริปต์
1. ใช้bind()
ฟังก์ชัน
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
หากคุณใช้underscore.js
- http://underscorejs.org/#bind
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
2 จัดเก็บการอ้างอิงบริบท / สิ่งนี้ภายในตัวแปรอื่น
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
3 ฟังก์ชั่นลูกศร
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
ทั้งหมดนี้อยู่ในไวยากรณ์ "magic" ของการเรียก method:
object.property();
เมื่อคุณได้รับคุณสมบัติจากวัตถุและเรียกใช้ในครั้งเดียววัตถุจะเป็นบริบทสำหรับวิธีการ หากคุณเรียกใช้วิธีเดียวกัน แต่ในขั้นตอนที่แยกจากกันบริบทจะเป็นขอบเขตส่วนกลาง (หน้าต่าง) แทน:
var f = object.property;
f();
เมื่อคุณได้รับการอ้างอิงของวิธีการจะไม่แนบกับวัตถุอีกต่อไปมันเป็นเพียงการอ้างอิงถึงฟังก์ชันธรรมดา สิ่งเดียวกันนี้จะเกิดขึ้นเมื่อคุณได้รับการอ้างอิงเพื่อใช้เป็นการโทรกลับ:
this.saveNextLevelData(this.setAll);
นั่นคือที่ที่คุณจะผูกบริบทเข้ากับฟังก์ชัน:
this.saveNextLevelData(this.setAll.bind(this));
หากคุณใช้ jQuery คุณควรใช้$.proxy
วิธีนี้แทนเนื่องจากbind
ไม่ได้รับการสนับสนุนในทุกเบราว์เซอร์:
this.saveNextLevelData($.proxy(this.setAll, this));
ปัญหาเกี่ยวกับ "บริบท"
คำว่า "บริบท" บางครั้งใช้ในการอ้างถึงวัตถุอ้างอิงจากนี้ การใช้งานที่ไม่เหมาะสมเพราะมันไม่พอดีทั้งความหมายในทางเทคนิคหรือมีECMAScript ของนี้
"บริบท"หมายถึงสถานการณ์รอบ ๆ สิ่งที่เพิ่มความหมายหรือข้อมูลก่อนหน้าและต่อไปนี้ที่ให้ความหมายพิเศษ คำว่า "บริบท" ถูกใช้ใน ECMAScript เพื่ออ้างถึงบริบทการดำเนินการซึ่งเป็นพารามิเตอร์ขอบเขตและสิ่งนี้ทั้งหมดภายในขอบเขตของโค้ดการดำเนินการบางส่วน
สิ่งนี้แสดงไว้ในECMA-262 หัวข้อ 10.4.2 :
ตั้งค่า ThisBinding เป็นค่าเดียวกับ ThisBinding ของบริบทการเรียกใช้งาน
ซึ่งบ่งชี้อย่างชัดเจนว่านี่เป็นส่วนหนึ่งของบริบทการดำเนินการ
บริบทการดำเนินการให้ข้อมูลโดยรอบที่เพิ่มความหมายให้กับโค้ดที่กำลังดำเนินการ ซึ่งจะรวมถึงข้อมูลเพิ่มเติมกว่าเพียงthisBinding
ดังนั้นคุณค่าของสิ่งนี้จึงไม่ใช่ "บริบท" แต่เป็นเพียงส่วนหนึ่งของบริบทการดำเนินการ โดยพื้นฐานแล้วเป็นตัวแปรท้องถิ่นที่สามารถตั้งค่าได้โดยการเรียกไปยังวัตถุใด ๆ และในโหมดเข้มงวดเป็นค่าใดก็ได้
คุณควรรู้เกี่ยวกับคำหลัก "นี้"
ตามมุมมองของฉันคุณสามารถใช้ "this" ได้สามวิธี (ฟังก์ชัน Self / Arrow / Bind Method)
คำหลักนี้ของฟังก์ชันทำงานแตกต่างกันเล็กน้อยใน JavaScript เมื่อเทียบกับภาษาอื่น ๆ
นอกจากนี้ยังมีความแตกต่างบางประการระหว่างโหมดเข้มงวดและโหมดไม่เข้มงวด
ในกรณีส่วนใหญ่ค่านี้จะถูกกำหนดโดยวิธีเรียกใช้ฟังก์ชัน
ไม่สามารถกำหนดโดยการมอบหมายระหว่างการดำเนินการและอาจแตกต่างกันในแต่ละครั้งที่เรียกใช้ฟังก์ชัน
ES5 แนะนำวิธีการผูก () เพื่อกำหนดค่าของฟังก์ชันนี้ไม่ว่าจะเรียกอย่างไร
และ ES2015 แนะนำฟังก์ชันลูกศรซึ่งไม่ได้ให้การเชื่อมโยงนี้เป็นของตัวเอง (จะยังคงรักษาค่านี้ของบริบทคำศัพท์ที่แนบมา)
วิธีที่ 1: Self - Self ถูกใช้เพื่อรักษาการอ้างอิงถึงต้นฉบับแม้ว่าบริบทจะเปลี่ยนไป เป็นเทคนิคที่มักใช้ในตัวจัดการเหตุการณ์ (โดยเฉพาะอย่างยิ่งในการปิด)
อ้างอิง : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
วิธีที่ 2 : ฟังก์ชันลูกศร - นิพจน์ฟังก์ชันลูกศรเป็นทางเลือกที่กระชับทางไวยากรณ์แทนนิพจน์ฟังก์ชันทั่วไป
แม้ว่าจะไม่มีการเชื่อมโยงของตัวเองกับคำหลักนี้อาร์กิวเมนต์ super หรือ new.target
นิพจน์ฟังก์ชันลูกศรไม่เหมาะกับวิธีการและไม่สามารถใช้เป็นตัวสร้างได้
อ้างอิง : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
Method3 : Bind- วิธีการผูก () สร้างฟังก์ชันใหม่ที่
เมื่อถูกเรียกจะมีการตั้งค่าคีย์เวิร์ดนี้เป็นค่าที่ระบุ
โดยมีลำดับของอาร์กิวเมนต์ที่กำหนดไว้ข้างหน้าเมื่อมีการเรียกใช้ฟังก์ชันใหม่
อ้างอิง: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
ครั้งแรกที่คุณจะต้องมีความเข้าใจอย่างชัดเจนscope
และพฤติกรรมของคำหลักในบริบทของthis
scope
this
& scope
:
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
ในระยะสั้นขอบเขตส่วนกลางหมายถึงวัตถุหน้าต่างตัวแปรที่ประกาศในขอบเขตทั่วโลกสามารถเข้าถึงได้จากทุกที่ในทางกลับกันขอบเขตของฟังก์ชันจะอยู่ภายในฟังก์ชันตัวแปรที่ประกาศภายในฟังก์ชันไม่สามารถเข้าถึงได้จากโลกภายนอกตามปกติ this
คำสำคัญในขอบเขตส่วนกลางหมายถึงวัตถุหน้าต่าง this
ภายในฟังก์ชั่นยังหมายถึงวัตถุหน้าต่างดังนั้นthis
จะอ้างถึงหน้าต่างเสมอจนกว่าเราจะพบวิธีจัดการthis
เพื่อระบุบริบทของการเลือกของเราเอง
--------------------------------------------------------------------------------
- -
- Global Scope -
- ( globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // outer function scope -
- // inside outer function"this" keyword refers to window object - -
- callback() // "this" inside callback also refers window object -
- } -
- -
- function callback_function(){ -
- -
- // function to be passed as callback -
- -
- // here "THIS" refers to window object also -
- -
- } -
- -
- outer_function(callback_function) -
- // invoke with callback -
--------------------------------------------------------------------------------
วิธีต่างๆในการจัดการthis
ฟังก์ชันการโทรกลับภายใน:
ที่นี่ฉันมีฟังก์ชันตัวสร้างที่เรียกว่าบุคคล มันมีคุณสมบัติที่เรียกว่าname
สี่และวิธีการที่เรียกว่าsayNameVersion1
, sayNameVersion2
, ,sayNameVersion3
sayNameVersion4
ทั้งสี่งานมีภารกิจเฉพาะอย่างหนึ่งยอมรับการโทรกลับและเรียกใช้การโทรกลับมีภารกิจเฉพาะซึ่งจะบันทึกคุณสมบัติชื่อของอินสแตนซ์ของฟังก์ชันตัวสร้างบุคคล
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// function to be used as callback
var parentObject = this
console.log(parentObject)
}
ตอนนี้เรามาสร้างอินสแตนซ์จากตัวสร้างบุคคลและเรียกใช้sayNameVersionX
เมธอด (X หมายถึง 1,2,3,4) เวอร์ชันต่างๆniceCallback
เพื่อดูว่าเราสามารถจัดการกับการthis
เรียกกลับภายในเพื่ออ้างถึงperson
อินสแตนซ์ได้กี่วิธี
var p1 = new Person('zami') // create an instance of Person constructor
สิ่งที่ผูกไว้คือการสร้างฟังก์ชันใหม่โดยthis
ตั้งค่าคีย์เวิร์ดเป็นค่าที่ระบุ
sayNameVersion1
และsayNameVersion2
ใช้การผูกเพื่อจัดการthis
กับฟังก์ชันเรียกกลับ
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
อันแรกผูกthis
กับการโทรกลับภายในวิธีการนั้นเองและสำหรับการโทรกลับครั้งที่สองจะถูกส่งผ่านไปพร้อมกับวัตถุที่ผูกไว้
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
first argument
ของcall
วิธีการที่จะใช้เป็นthis
ภายในฟังก์ชันที่ถูกเรียกด้วยcall
แนบมากับมัน
sayNameVersion3
ใช้ call
เพื่อจัดการthis
เพื่ออ้างถึงวัตถุบุคคลที่เราสร้างขึ้นแทนที่จะเป็นวัตถุหน้าต่าง
this.sayNameVersion3 = function(callback){
callback.call(this)
}
และเรียกว่าดังต่อไปนี้:
p1.sayNameVersion3(niceCallback)
คล้ายกับcall
อาร์กิวเมนต์แรกของการapply
อ้างถึงวัตถุที่จะระบุด้วยthis
คำสำคัญ
sayNameVersion4
ใช้apply
ในการจัดการthis
เพื่ออ้างถึงวัตถุบุคคล
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
และเรียกว่าดังต่อไปนี้เพียงแค่โทรกลับเท่านั้น
p1.sayNameVersion4(niceCallback)
เราไม่สามารถผูกสิ่งนี้เข้าsetTimeout()
กับมันได้เนื่องจากมันมักจะเรียกใช้กับglobal object (Window)เสมอหากคุณต้องการเข้าถึงthis
บริบทในฟังก์ชัน callback โดยใช้bind()
กับฟังก์ชัน callback ที่เราสามารถทำได้เป็น:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
คำถามเกี่ยวกับการthis
ทำงานของคำหลักในจาวาสคริปต์ this
ทำงานแตกต่างกันดังต่อไปนี้
- ค่าของ
this
มักจะถูกกำหนดโดยบริบทการเรียกใช้ฟังก์ชัน - ในขอบเขตส่วนกลาง
this
หมายถึงวัตถุส่วนกลาง (window
วัตถุ) - หากเปิดใช้งานโหมดเข้มงวดสำหรับฟังก์ชันใด ๆ ค่าของ
this
จะundefined
เป็นในโหมดเข้มงวดวัตถุส่วนกลางจะอ้างถึงundefined
ในตำแหน่งของwindow
วัตถุ - ออบเจ็กต์ที่อยู่หน้าจุดคือสิ่งที่คีย์เวิร์ดนี้จะถูกผูกไว้
- เราสามารถตั้งค่านี้อย่างชัดเจนด้วย
call()
,bind()
และapply()
- เมื่อใช้
new
คีย์เวิร์ด (ตัวสร้าง) สิ่งนี้จะถูกผูกไว้กับอ็อบเจ็กต์ใหม่ที่กำลังสร้าง - ฟังก์ชั่นลูกศรไม่ผูก
this
- ผูกthis
เป็นศัพท์แทน (กล่าวคือขึ้นอยู่กับบริบทเดิม)
ตามที่คำตอบส่วนใหญ่แนะนำเราสามารถใช้ฟังก์ชัน Arrow หรือbind()
Method หรือ Self var ฉันจะพูดถึงประเด็นเกี่ยวกับ lambdas (ฟังก์ชัน Arrow) จากGoogle JavaScript Style Guide
ชอบใช้ฟังก์ชันลูกศรมากกว่า f.bind (this) และโดยเฉพาะอย่างยิ่งใน goog.bind (f, this) หลีกเลี่ยงการเขียน const self = this ฟังก์ชันลูกศรมีประโยชน์อย่างยิ่งสำหรับการเรียกกลับซึ่งบางครั้งอาจส่งผ่านข้อโต้แย้งเพิ่มเติมโดยไม่คาดคิด
Google แนะนำอย่างชัดเจนว่าให้ใช้ lambdas แทนการผูกหรือ const self = this
ดังนั้นทางออกที่ดีที่สุดคือใช้ lambdas ดังต่อไปนี้
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
อ้างอิง:
ปัจจุบันมีแนวทางอื่นที่เป็นไปได้หากใช้คลาสในโค้ด
ด้วยการสนับสนุนฟิลด์คลาส จึงเป็นไปได้ที่จะดำเนินการต่อไปนี้:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // this refers to correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
แน่นอนว่าภายใต้ประทุนมันเป็นฟังก์ชันลูกศรที่ดีที่ผูกบริบท แต่ในรูปแบบนี้มันดูชัดเจนกว่ามากว่าการเชื่อมโยงอย่างชัดเจน
เนื่องจากเป็นข้อเสนอขั้นที่ 3 คุณจะต้องใช้ babel และปลั๊กอิน babelที่เหมาะสมเพื่อดำเนินการในตอนนี้ (08/2018)
อีกวิธีหนึ่งซึ่งเป็นวิธีมาตรฐานตั้งแต่ DOM2ในการเชื่อมโยงthis
ภายในตัวฟังเหตุการณ์ที่ช่วยให้คุณลบ Listener ได้ตลอดเวลา (ท่ามกลางประโยชน์อื่น ๆ ) คือhandleEvent(evt)
วิธีการจากEventListener
อินเทอร์เฟซ:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
สามารถดูข้อมูลโดยละเอียดเกี่ยวกับการใช้งานhandleEvent
ได้ที่นี่: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38
this
ใน JS:
ค่าของthis
ใน JS คือ 100% กำหนดโดยวิธีเรียกใช้ฟังก์ชันไม่ใช่วิธีกำหนด เราสามารถหาได้ง่ายค่อนข้างค่าของthis
โดย'ซ้ายของกฎ dot' :
- เมื่อฟังก์ชันถูกสร้างขึ้นโดยใช้คีย์เวิร์ดของฟังก์ชันค่าของ
this
จะเป็นอ็อบเจ็กต์ทางซ้ายของจุดของฟังก์ชันที่เรียกว่า - หากไม่มีวัตถุเหลือจากจุดค่าของ
this
ภายในฟังก์ชันมักจะเป็นวัตถุส่วนกลาง (global
ในโหนดwindow
ในเบราว์เซอร์) ฉันไม่แนะนำให้ใช้this
คำหลักที่นี่เพราะมีความชัดเจนน้อยกว่าการใช้คำหลักเช่นwindow
! - มีโครงสร้างบางอย่างเช่นฟังก์ชันลูกศรและฟังก์ชันที่สร้างขึ้นโดยใช้
Function.prototype.bind()
ฟังก์ชันที่สามารถแก้ไขค่าของthis
. เหล่านี้เป็นข้อยกเว้นของกฎthis
แต่จริงๆเป็นประโยชน์ในการแก้ไขปัญหาค่าของ
ตัวอย่างใน nodeJS
module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);
const obj1 = {
data: "obj1 data",
met1: function () {
console.log(this.data);
},
met2: () => {
console.log(this.data);
},
};
const obj2 = {
data: "obj2 data",
test1: function () {
console.log(this.data);
},
test2: function () {
console.log(this.data);
}.bind(obj1),
test3: obj1.met1,
test4: obj1.met2,
};
obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);
เอาท์พุต:
ให้ฉันแนะนำคุณเกี่ยวกับเอาต์พุต 1 ต่อ 1 (ละเว้นบันทึกแรกเริ่มจากวินาที):
this
เป็นobj2
เพราะด้านซ้ายของกฎจุดเราจึงสามารถดูได้ว่าtest1
ถูกเรียกobj2.test1();
อย่างไรobj2
ทางซ้ายของจุดจึงเป็นthis
ค่า- แม้ว่าจะ
obj2
เหลืออยู่ในจุดที่test2
ถูกผูกไว้กับobj1
ผ่านทางbind()
วิธีการ ดังนั้นค่าthis
obj1
obj2
อยู่ทางซ้ายของจุดจากฟังก์ชันที่เรียกว่า:obj2.test3()
. จึงobj2
จะเป็นค่าของthis
.- ในกรณีนี้:
obj2.test4()
obj2
อยู่ทางซ้ายของจุด อย่างไรก็ตามฟังก์ชันลูกศรไม่มีการthis
เชื่อมโยงของตัวเอง ดังนั้นมันจะผูกกับthis
ค่าของขอบเขตภายนอกซึ่งเป็นmodule.exports
อ็อบเจ็กต์ที่ถูกบันทึกในตอนต้น - เรายังสามารถระบุค่าของ
this
โดยใช้call
ฟังก์ชัน ที่นี่เราสามารถส่งผ่านthis
ค่าที่ต้องการเป็นอาร์กิวเมนต์ซึ่งobj2
ในกรณีนี้
ฉันกำลังเผชิญปัญหากับNgx
แผนภูมิเส้นxAxisTickFormatting
ฟังก์ชั่นซึ่งถูกเรียกจาก HTML [xAxisTickFormatting]="xFormat"
เช่นนี้ ฉันไม่สามารถเข้าถึงตัวแปรของส่วนประกอบของฉันจากฟังก์ชันที่ประกาศไว้ วิธีนี้ช่วยฉันในการแก้ไขปัญหาเพื่อค้นหาสิ่งที่ถูกต้อง หวังว่านี่จะช่วยให้Ngx
แผนภูมิเส้นผู้ใช้
แทนที่จะใช้ฟังก์ชันเช่นนี้:
xFormat (value): string {
return value.toString() + this.oneComponentVariable; //gives wrong result
}
ใช้สิ่งนี้:
xFormat = (value) => {
// console.log(this);
// now you have access to your component variables
return value + this.oneComponentVariable
}