ฟังก์ชั่นการโทร
ฟังก์ชั่นเป็นเพียงประเภทของวัตถุ
วัตถุฟังก์ชั่นทั้งหมดมีการโทรและใช้วิธีการที่รันวัตถุฟังก์ชั่นที่พวกเขาเรียกว่า
เมื่อเรียกว่าอาร์กิวเมนต์แรกวิธีการเหล่านี้ระบุวัตถุซึ่งจะถูกอ้างอิงโดยthis
คำหลักระหว่างการทำงานของฟังก์ชั่น - ถ้ามันเป็นnull
หรือundefined
วัตถุทั่วโลกจะถูกใช้สำหรับwindow
this
ดังนั้นการเรียกฟังก์ชั่น ...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
... ที่มีวงเล็บ - foo()
- เทียบเท่ากับfoo.call(undefined)
หรือfoo.apply(undefined)
ซึ่งเป็นได้อย่างมีประสิทธิภาพเช่นเดียวกับหรือfoo.call(window)
foo.apply(window)
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
อาร์กิวเมนต์เพิ่มเติมที่จะcall
ถูกส่งผ่านเป็นอาร์กิวเมนต์ไปยังการเรียกใช้ฟังก์ชันในขณะที่อาร์กิวเมนต์เพิ่มเติมเพียงครั้งเดียวที่apply
สามารถระบุอาร์กิวเมนต์สำหรับการเรียกฟังก์ชันเป็นวัตถุแบบ Array
ดังนั้นfoo(1, 2, 3)
จะเทียบเท่ากับหรือfoo.call(null, 1, 2, 3)
foo.apply(null, [1, 2, 3])
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
ถ้าฟังก์ชั่นเป็นคุณสมบัติของวัตถุ ...
var obj =
{
whereAmI: "obj",
foo: foo
};
... การเข้าถึงการอ้างอิงถึงฟังก์ชั่นผ่านทางวัตถุและเรียกมันว่าด้วยวงเล็บ - obj.foo()
- เทียบเท่ากับหรือfoo.call(obj)
foo.apply(obj)
อย่างไรก็ตามฟังก์ชั่นที่ถูกจัดเก็บเป็นคุณสมบัติของวัตถุนั้นไม่ได้ถูก "ผูกไว้" กับวัตถุเหล่านั้น ดังที่คุณเห็นในนิยามของobj
ข้างต้นเนื่องจากฟังก์ชั่นเป็นเพียงประเภทของวัตถุพวกเขาสามารถอ้างอิงได้ (และสามารถส่งผ่านโดยการอ้างอิงถึงการเรียกใช้ฟังก์ชันหรือส่งคืนโดยการอ้างอิงจากการเรียกใช้ฟังก์ชัน) เมื่อมีการอ้างอิงถึงฟังก์ชั่นที่มีการส่งผ่านไปไม่มีข้อมูลเพิ่มเติมเกี่ยวกับการที่มันถูกส่งผ่านจากจะดำเนินการกับมันซึ่งเป็นเหตุผลต่อไปนี้เกิดขึ้น:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
เรียกร้องให้การอ้างอิงฟังก์ชั่นของเราbaz
ไม่ได้ให้บริบทใด ๆ สำหรับการโทรเพื่อให้มันได้อย่างมีประสิทธิภาพเช่นเดียวกับbaz.call(undefined)
เพื่อให้ปลายขึ้นอ้างอิงthis
window
หากเราต้องการbaz
รู้ว่ามันเป็นของobj
เราจำเป็นต้องให้ข้อมูลที่เมื่อbaz
มีการเรียกซึ่งเป็นที่ที่อาร์กิวเมนต์แรกcall
หรือapply
ปิดและเข้ามาเล่น
ขอบเขตโซ่
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
เมื่อมีการใช้งานฟังก์ชั่นมันจะสร้างขอบเขตใหม่และมีการอ้างอิงถึงขอบเขตที่ล้อมรอบ เมื่อฟังก์ชั่นที่ไม่ระบุชื่อถูกสร้างขึ้นในตัวอย่างข้างต้นมันมีการอ้างอิงถึงขอบเขตที่มันถูกสร้างขึ้นในซึ่งเป็นbind
ขอบเขตของ สิ่งนี้เรียกว่า "การปิด"
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
เมื่อคุณพยายามเข้าถึงตัวแปร "ขอบเขตลูกโซ่" นี้จะเดินไปหาตัวแปรที่มีชื่อที่กำหนด - ถ้าขอบเขตปัจจุบันไม่มีตัวแปรคุณจะดูขอบเขตถัดไปในลูกโซ่และต่อ ๆ ไปจนกว่าจะถึง ขอบเขตทั่วโลก เมื่อฟังก์ชันที่ไม่ระบุชื่อถูกส่งคืนและbind
ดำเนินการเสร็จสิ้นฟังก์ชันที่ไม่ระบุชื่อจะยังคงมีการอ้างอิงถึงbind
ขอบเขตของดังนั้นbind
ขอบเขตของจะไม่ "หายไป"
จากข้างต้นทั้งหมดคุณควรจะสามารถเข้าใจวิธีการทำงานของขอบเขตในตัวอย่างต่อไปนี้และทำไมเทคนิคสำหรับการส่งผ่านฟังก์ชันรอบ "pre-bound" ด้วยค่าเฉพาะของthis
มันจะมีเมื่อเรียกว่าทำงาน:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};