Friday, March 10, 2006

Pattern การ implement Object ใน Prototype.js (1.4.0)

style ปกติที่เราใช้สร้าง javascript object
ก็คือการใช้ function
ตัวอย่าง

function Person(name, age) {
this.name = name;
this.age = age;
this.dump = function() {
return this.name + ", " + this.age;
}
}

var p = new Person("pann", 1);

ซึ่งก็มีหลายคนออกมาชี้ว่า
วิธีนี้ ถ้าเรามี object จำนวนมาก
มันจะเปลือง memory นะ, เพราะ method dump
มันถูก declare ขึ้นมา 1 function ต่อ 1 object
ก็เลยมีการพลิกแพลงออกไปใช้ prototype
(เวลา javascript object ถูกเรียกใช้งาน มันจะมองหา attribute ภายใน
scope ของมันก่อน ถ้าไม่เจอก็จะค้นหาจาก object ที่ pointer prototype ชี้อยู่)

function Person(name, age) {
this.name = name;
this.age = age;
}

Person.prototype = {
dump: function() {
return this.name + ", " + this.age;
}
}


Prototype.js ก็เห็นดีเห็นงามกับแนวทางที่ 2 (อันนี้เป็นสาเหตุ ว่าทำไม library ถึงชื่อ prototype)
แต่ตบแต่ง style เสียใหม่
ได้หน้าตา การประกาศ object ออกมาแบบนี้

var Person = Class.create();

Person.prototype = {
initialize: function(name, age) {
this.name = name;
this.age = age;
},

dump: function() {
return this.name + ", " + this.age;
}
}

ซึ่งก็ดูดีขึ้นนะ (ถ้าเข้าใจว่ามันทำงานอย่างไร)
magic อยู่ที่ function Class

var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}

เมื่อเราเรียก var Person = Class.create()
ตัวแปร Person จะชี้ไปยัง function ที่ return กลับออกมาจาก Class object
และเมื่อเราเรียก Person.new ก็จะเกิดการเรียกใช้ function ที่ชื่อ initialize
ซึ่งถูก declare ไว้ใน Person.prototype object

เมื่อมี object แล้วก็ต้องมีการ extend หรือ inheritance
ใครที่มาจากสาย java แล้วใช้ความคิดแบบ java เข้ามาจับ
รับรองว่าได้ปวดหัวกับการ debug แน่นอน
คำแนะนำที่ดี ก็คือ อย่า design แบบ deep hierachy tree เลย
พวก polymorphic หรือ overloading
ก็อย่าไปนึกถึง

แต่ถ้าอยากลองดู ลองอ่านอันนี้ดู Object Hierarchy and Inheritance in Javascript
ซึ่งดูเหมือนจะเป็น technique แบบเก่า
ถ้าอยากได้แบบใหม่ๆหน่อย ก็ลองอ่านนี่ดู
Javascript Inheritance
แต่ผมไม่ค่อยชอบ technique ที่เขาแนะนำเท่าไร
มันดูแปลกๆในส่วนของการ copyPrototype

ใน Prototype.js ก็มี method extend ให้ใช้เหมือนกัน
แต่ส่วนใหญ่จะใช้ในลักษณะของ Mixin แบบ ruby เสียมากกว่า
โดยการ design จะใช้วิธีเสริม function เข้าไปใน object ที่มีอยู่แล้ว
เช่น

var Enumerable = {
...

findAll: function(iterator) {
var results = [];
this.each(function(value, index) {
if (iterator(value, index))
results.push(value);
});
return results;
},

...
}

Object.extend(Array.prototype, Enumerable);

ทำให้เราสามารถทำแบบนี้ได้


[1,2,3].findAll(function(value) {
return value > 1;
})
// => [2,3]

Related link from Roti

2 comments:

Pete[cs@requidjobs.com] said...

พอดี search เรื่อง prototype framework จาก google แล้วมาเจอ blog ของคุณน่ะครับ เลยมีคำถามอยากรบกวนนิดนึงครับ

คือเวลาผมใช้ prototype ส่ง parameter เนี่ยมันก็จะอยู่ในรูป 'name=abcd&surname=refd' ใช่ไหมครับ ที่อยากถามคือถ้าหากผมมีตัวแปรชื่อ check เป็น array รับค่ามาจาก checkbox ในเว็บเพจเนี่ย

การส่งตัวแปรแบบ array สามารถทำได้หรือเปล่าครับ

polawat phetra said...

ผมตอบไว้ในนี้ครับ
http://pphetra.blogspot.com/2006/11/prototype-parameter.html