ช่วงนี้มีโปรเจคที่ต้องเขียน Javascript อย่างหนักหน่วง ก็เลยมีเวลาได้อ่านเรื่อง bind, call, apply ซึ่งเป็นวิธีจัดการกับ Function ที่ยืดหยุ่นกว่าสิ่งที่เคยได้ร่ำเรียนมาในระดับมหาวิทยาลัย เพื่อไม่ให้ลืม (เพราะเอาเข้าจริง ๆ ถ้าไม่ได้เขียนบ่อย ๆ ก็คงลืม) ก็เลยขอสรุปย่อ ๆ ไว้ ณ ที่นี้
bind
, call
, และ apply
เป็น method พิเศษที่มากับ function ในภาษา Javascript (call
และ apply
มาในช่วง ECMAScript 3 แถว ๆ IE 6 ส่วน bind
มาใน ECMAScript 5 แถว ๆ IE 10) วิธีประกาศ function ในภาษา Javascript นั้นสามารถทำได้ 2 แบบคือ
function hello(a, b, c) { }
หรือ
var hello = function (a, b, c) { }
ฟังก์ขั่น hello
ตามตัวอย่างนี้มี argument 3 ตัวคือ a, b, c แต่จริง ๆ แล้วภายในฟังก์ชั่นนี้ (หรือที่อื่น ๆ) ยังมีตัวแปรลับอีกตัวคือ this
ซึ่งค่าจะขึ้นกับบริบทที่มันถูกใช้งาน เช่น หากมันถูกเรียกจาก event ต่าง ๆ มันอาจจะกลายเป็น HTMLElement ของ event นั้นหรือถ้าเรียกลอย ๆ เลยก็จะเป็น window
นั่นก็นำมาสู่ปัญหาเมื่อมีการอ้างถึง this
ภายในฟังก์ชั่นว่า ตกลงว่า this
นี่คืออะไรกันแน่? bind
, call
, และ apply
เกิดมาเพื่อบังคับให้ this
เป็นค่าที่เราต้องการได้
call
และ apply
เรียกฟังก์ชั่นโดยการกำหนดค่า this
call
และ apply
นั้น เป็นวิธีเรียกใช้งานฟังก์ชั่น โดยกำหนดค่า this
เมื่อต้องใช้งาน แต่สิ่งที่แตกต่างคือ call
นั้นรับค่าเป็นตัวแปรธรรมดา แต่ apply
รับค่าเป็น array
var r1 = hello.call("5", "a", "b", "c");
var r2 = hello.apply("5", ["a", "b", "c"]);
จากตัวอย่างนี้ ทั้ง call
และ apply
เป็นการเรียก hello
ที่ค่าของ this
เป็น "5" แต่ที่ต่างคือ ท่อนหลังของ call
เป็นการส่งค่าให้ a
, b
, c
เป็น "a", "b", "c" ตามลำดับ แต่ส่วนของ apply
นั้นส่ง array ไปแทนและค่าจะถูกแตกให้กับ a
, b
, c
เป็น "a", "b", "c" ตามลำดับ
bind
ผูก argument ให้กับฟังก์ชั่นเดิม กลายเป็นฟังก์ชั่นใหม่
bind
เป็น method พิเศษที่มากับฟังก์ชั่น (IE < 9, Firefox < 3 ใช้ไม่ได้) จุดประสงค์ของมันในตอนแรก ใช้เพื่อห่อฟังก์ชั่นเดิม ให้กลายเป็นฟังก์ชั่นใหม่ที่ถูกตั้งค่า argument บางอย่างไว้ (ต่างกับ apply
และ call
ที่เป็นการเรียกใช้ฟังก์ชั่นตรง ๆ)
การเรียก bind
กับ hello
นี้จะทำให้เกิดฟังก์ชั่นใหม่ เช่น
var hello2 = hello.bind("5");
hello2("a", "b", "c");
จากตัวอย่างนี้ เราจะได้ฟังก์ชั่น hello2
ซึ่งเมื่อเรียกใช้งานจะเสมือนการเรียก hello
เพียงแต่ว่าหากใน hello
มีการกล่าวถึง this
ค่าของ this
จะมีค่า "5" ค่า a
, b
, c
เป็นไปตามลำดับที่เรียก นั่นคือ "a", "b", "c"
var hello3 = hello.bind("5", "z");
var r3 = hello3("b", "c");
จากตัวอย่างนี้ เราจะได้ฟังก์ชั่น hello3
ซึ่งเมื่อเรียกใช้งานจะเสมือนการเรียก hello
เพียงแต่คราวนี้ ทั้ง this
และ a
จะถูกกำหนดค่าเป็น "5" และ "z" ตามลำดับ ส่วนค่าของ b
, c
เป็นไปตามลำดับที่เรียก นั่นคือ "b", "c" ผลลัพธ์ที่ได้ (ถ้ามี return ใน hello
) ก็คือ r3
ตัวอย่างการใช้งานอื่น ๆ เช่น จะผูก hello เข้ากับการกดปุ่ม (สมมติว่ามี id เป็น test) แต่ต้องการบังคับ this
และ argument อื่น ก็สามารถทำได้ดังนี้
document.querySelector('#test').addEventListener('click', hello.bind('5', 'a', 'b', 'c'));
แล้วจะเขียนให้ยากทำไมล่ะ?
บางครั้งการที่นำ code มาจากแหล่งอื่นแล้วในนั้นมีการอ้างถึง this
(ซึ่งหากเล่นกันถึงขนาดนี้แล้ว code มันคงไม่ใช่ hello world ง่าย ๆ แน่ น่าจะมีการเขียนเป็น Javascript Object) หากเรานำโค้ดไปใช้เลยก็อาจจะทำให้มันทำงานไม่เหมือนแหล่งต้นทางที่ไปเอา code มาก็ได้ เราจึงต้องการกำหนด this
ซึ่งการเรียกใช้งาน hello
ตามปรกติ จะไม่สามารถทำสิ่งนี้ได้ แต่ทั้งนี้ก็ขึ้นกับนักพัฒนาว่าจะนำเอารูปแบบการเขียนโค้ดนี้ไปใช้ประยุกต์กับอะไร