Friday, May 02, 2008

this ใน javascript กับ dojo.hitch

ใน javascript, bug ที่พบกันบ่อยๆ ก็คือ scope ของ this ที่มักไม่ได้เป็นไปตามที่ programmer คิด
ยกตัวอย่าง
<a id='linkNode' href="#">link</a>
<script>
foo = {

greeting: 'hi',

debug: function() {
alert(this.greeting);
}
}

document.getElementById('linkNode').onclick = foo.debug;
</script>

ถ้าลอง run code ข้างบนนี้ดู ก็จะพบว่า ถ้าเรา click link นั้นเมื่อไร
message ที่แสดงใน alert มันจะแสดงคำว่า "undefined" แทนที่จะเป็น 'hi'
ที่เป็นเช่นนี้ก็เพราะว่า this object ใน function debug ณ ขณะที่เกิด event
function มันจะเปลี่ยน scope ทำให้ this กลายเป็น DOM element ของ anchor แทนที่จะเป็น object foo

แล้ว dojo.hitch หล่ะคืออะไร
function นี้ในแง่ของ functional language ถือว่ามันเป็น higher order function
เนื่องจากมันเป็น function ที่ return function

หน้าที่หลักของ dojo.hitch ก็คือการ bind scope ของ function เข้ากับ object ที่เราต้องการ
อย่างตัวอย่างข้างบน ถ้าเรานำ dojo.hitch มาช่วย ก็จะเขียนเป็นแบบนี้แทน
document.getElementById('linkNode').onclick = dojo.hitch(foo, "debug");

ถ้าลอง run ดู ก็จะได้ message 'hi' ขึ้นมา

จะเห็นว่า hitch ช่วยเราเปลี่ยน scope ของ this จากเดิมที่เป็น DOM element (ที่ trig event นั้น) ให้กลายเป็น foo object แทน โดยใช้ technique การ binding
ลองมาดู code ของ function hitch กัน

dojo.hitch = function(scope, method){
if(arguments.length > 2){
return dojo._hitchArgs.apply(dojo, arguments); // Function
}
if(!method){
method = scope;
scope = null;
}
if(dojo.isString(method)){
scope = scope || dojo.global;
if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
return function(){ return scope[method].apply(scope, arguments || []); };
}
return !scope ? method : function(){ return method.apply(scope, arguments || []); };
}

เริ่มต้นด้วย การข้าม case กรณี arguments​ > 2 ไปก่อนเลย
อันนั้นเป็นเงื่อนไขพิเศษ กรณีที่ต้องการให้มี fixed(prefix) arguments.

ส่วนถัดมาก็คือส่วน ตรวจสอบว่า มีการ pass parameter มาตัวเดียวหรือเปล่า
ถ้ามาตัวเดียว ก็จะถือว่า parameter นั้นเป็น method

สุดท้ายก็ตรวจสอบอีกว่า method เป็น string
หรือเป็น string ก็จะ return closure ที่ห่อคำสั่ง scope[method].apply
ถ้าไม่ใช่ script ก็จะ return closure ที่ใช้คำสั่ง method.apply แทน

อืมม์พอเริ่มเข้าใจ ก็เริ่มเห็นความงาม

ถ้าใครสนใจอยากอ่านให้เข้าใจ(หรืองง)เข้าไปอีก อ่านเพิ่มเติมที่นี่
Jammastergoat - dojo.hitch

Related link from Roti

1 comment:

veer said...

ดูสวยงามดี :-)