สิ่งที่คุณควรรู้ this
this(aka "บริบท") เป็นคำหลักพิเศษภายในแต่ละฟังก์ชั่นและมูลค่าของมันขึ้นอยู่กับวิธีการเรียกใช้ฟังก์ชั่นไม่ใช่วิธี / เมื่อ / ที่มันถูกกำหนด มันไม่ได้รับผลกระทบจากขอบเขตศัพท์เช่นตัวแปรอื่น ๆ (ยกเว้นฟังก์ชั่นลูกศรดูด้านล่าง) นี่คือตัวอย่างบางส่วน:
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
อย่าใช้ this
จริงๆคุณไม่ต้องการที่จะเข้าถึงthisโดยเฉพาะอย่างยิ่ง แต่วัตถุที่มันหมายถึง นั่นเป็นสาเหตุที่ทางออกที่ง่ายคือเพียงสร้างตัวแปรใหม่ที่อ้างอิงถึงวัตถุนั้น ตัวแปรสามารถมีชื่อใด ๆ แต่คนทั่วไปและselfthat
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
เนื่องจากselfเป็นตัวแปรปกติจึงเป็นไปตามกฎขอบเขตคำศัพท์และสามารถเข้าถึงได้ภายในการเรียกกลับ สิ่งนี้ยังมีข้อดีที่คุณสามารถเข้าถึงthisมูลค่าของการโทรกลับได้
ชุดthisโทรกลับ - ส่วนที่ 1 อย่างชัดเจน
อาจดูเหมือนว่าคุณไม่สามารถควบคุมค่าได้thisเนื่องจากค่าถูกตั้งค่าโดยอัตโนมัติ แต่นั่นไม่ใช่กรณี
ทุกฟังก์ชั่นมีเมธอด.bind [เอกสาร]ซึ่งจะส่งคืนฟังก์ชันใหม่ที่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ค่าของ'sMyConstructorthis
หมายเหตุ:เมื่อเชื่อมโยงบริบทสำหรับ jQuery ให้ใช้jQuery.proxy [docs]แทน เหตุผลในการทำเช่นนี้คือเพื่อให้คุณไม่จำเป็นต้องจัดเก็บข้อมูลอ้างอิงไปยังฟังก์ชันเมื่อยกเลิกการเชื่อมโยงการเรียกกลับเหตุการณ์ jQuery จัดการภายในนั้น
ECMAScript 6 แนะนำฟังก์ชั่นลูกศรซึ่งถือได้ว่าเป็นฟังก์ชั่นแลมบ์ดา พวกเขาไม่มีthisผลผูกพัน แต่thisจะค้นหาในขอบเขตเหมือนตัวแปรปกติ .bindนั่นหมายความว่าคุณจะได้ไม่ต้องโทร นี่ไม่ใช่พฤติกรรมพิเศษเท่านั้นที่มีโปรดดูเอกสาร MDN สำหรับข้อมูลเพิ่มเติม
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
ชุดthisโทรกลับ - ส่วนที่ 2
ฟังก์ชั่น / วิธีการบางอย่างที่ยอมรับการเรียกกลับยังยอมรับค่าที่thisควรใช้ในการติดต่อกลับ นี่เป็นพื้นฐานเหมือนกับการผูกมันด้วยตัวคุณเอง แต่ฟังก์ชั่น / วิธีการทำเพื่อคุณ Array#map [เอกสาร]เป็นวิธีการดังกล่าว ลายเซ็นของมันคือ:
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 [docs]$.ajaxอธิบายถึงตัวเลือกที่เรียกว่าcontext:
วัตถุนี้จะทำให้บริบทของการเรียกกลับที่เกี่ยวข้องกับอาแจ็กซ์ทั้งหมด
ปัญหาทั่วไป: การใช้วิธีการวัตถุเป็นตัวเรียกกลับ / ตัวจัดการเหตุการณ์
การประกาศทั่วไปของปัญหานี้คือเมื่อมีการใช้วิธีการวัตถุเป็นตัวจัดการการติดต่อกลับ / เหตุการณ์ ฟังก์ชั่นเป็นพลเมืองชั้นหนึ่งใน JavaScript และคำว่า "method" เป็นเพียงคำศัพท์สำหรับฟังก์ชั่นที่เป็นค่าของคุณสมบัติวัตถุ แต่ฟังก์ชั่นนั้นไม่มีลิงค์เฉพาะไปยังวัตถุ "บรรจุ"
ลองพิจารณาตัวอย่างต่อไปนี้:
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();