ดังต่อไปนี้สารสกัดจากปิด: คู่มือการแตกหักโดยไมเคิล Bolin มันอาจดูยาวไปหน่อย แต่ก็อิ่มตัวด้วยความเข้าใจอย่างถ่องแท้ จาก "ภาคผนวก B. แนวคิดเกี่ยวกับ JavaScript ที่เข้าใจผิดบ่อย":
this
หมายถึงอะไรเมื่อมีการเรียกใช้ฟังก์ชั่น
เมื่อเรียกใช้ฟังก์ชันของฟอร์มfoo.bar.baz()
วัตถุfoo.bar
จะถูกเรียกว่าผู้รับ เมื่อเรียกใช้ฟังก์ชันจะเป็นผู้รับที่ใช้เป็นค่าสำหรับthis
:
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
หากไม่มีตัวรับสัญญาณที่ชัดเจนเมื่อมีการเรียกใช้ฟังก์ชันวัตถุกลางจะกลายเป็นผู้รับ ตามที่อธิบายไว้ใน "goog.global" ในหน้า 47 หน้าต่างเป็นวัตถุร่วมเมื่อเรียกใช้ JavaScript ในเว็บเบราว์เซอร์ สิ่งนี้นำไปสู่พฤติกรรมที่น่าประหลาดใจ:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
ถึงแม้ว่าobj.addValues
และf
อ้างถึงฟังก์ชั่นเดียวกันพวกเขาจะทำงานแตกต่างกันเมื่อถูกเรียกเพราะค่าของผู้รับนั้นแตกต่างกันในการโทรแต่ละครั้ง ด้วยเหตุผลนี้เมื่อเรียกใช้ฟังก์ชันที่อ้างถึงthis
เป็นสิ่งสำคัญเพื่อให้แน่ใจว่าthis
จะมีค่าที่ถูกต้องเมื่อมีการเรียกใช้ จะมีความชัดเจนหากthis
ไม่ได้อ้างอิงในร่างกายของฟังก์ชั่นแล้วพฤติกรรมของf(20)
และobj.addValues(20)
จะเหมือนกัน
เนื่องจากฟังก์ชั่นเป็นวัตถุชั้นหนึ่งใน JavaScript พวกเขาสามารถมีวิธีการของตัวเอง ฟังก์ชั่นทั้งหมดมีวิธีการcall()
และapply()
ทำให้สามารถกำหนดตัวรับสัญญาณใหม่ (เช่นวัตถุที่this
อ้างถึง) เมื่อเรียกใช้ฟังก์ชัน ลายเซ็นวิธีการมีดังนี้:
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
โปรดทราบว่าความแตกต่างเพียงอย่างเดียวระหว่างcall()
และapply()
คือที่call()
ได้รับพารามิเตอร์ฟังก์ชั่นเป็นข้อโต้แย้งของแต่ละบุคคลในขณะที่apply()
ได้รับพวกเขาเป็นอาร์เรย์เดียว:
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
การเรียกต่อไปนี้เทียบเท่าf
และและobj.addValues
อ้างอิงถึงฟังก์ชันเดียวกัน:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
อย่างไรก็ตามเนื่องจากcall()
มิได้apply()
ใช้ค่าของผู้รับเองเพื่อทดแทนอาร์กิวเมนต์ผู้รับเมื่อไม่ระบุรายละเอียดต่อไปนี้จะไม่ทำงาน:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
ค่าของthis
ไม่สามารถเป็นได้null
หรือundefined
เมื่อเรียกใช้ฟังก์ชัน เมื่อnull
หรือundefined
จัดหาเป็นผู้รับถึงcall()
หรือapply()
วัตถุส่วนกลางจะใช้เป็นค่าสำหรับผู้รับแทน ดังนั้นรหัสก่อนหน้ามีผลข้างเคียงที่ไม่พึงประสงค์เหมือนกันของการเพิ่มคุณสมบัติที่มีชื่อvalue
วัตถุทั่วโลก
การคิดฟังก์ชั่นอาจช่วยได้หากไม่มีความรู้เกี่ยวกับตัวแปรที่ได้รับมอบหมาย สิ่งนี้จะช่วยเสริมความคิดที่ว่าคุณค่าของสิ่งนี้จะถูกผูกไว้เมื่อเรียกใช้ฟังก์ชันแทนเมื่อถูกกำหนด
ในตอนท้ายของสารสกัด
a
ใช้กับอาร์เรย์ของ args และใช้c
เรียกคอลัมน์ args