สิ่งที่คุณควรรู้ 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
โดยเฉพาะอย่างยิ่ง แต่วัตถุที่มันหมายถึง นั่นเป็นสาเหตุที่ทางออกที่ง่ายคือเพียงสร้างตัวแปรใหม่ที่อ้างอิงถึงวัตถุนั้น ตัวแปรสามารถมีชื่อใด ๆ แต่คนทั่วไปและself
that
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
ค่าของ'sMyConstructor
this
หมายเหตุ:เมื่อเชื่อมโยงบริบทสำหรับ 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();