ดังต่อไปนี้สารสกัดจากปิด: คู่มือการแตกหักโดยไมเคิล 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