Monday, July 12, 2010

"new" operator in javascript

ช่วงนี้ได้มีโอกาสสอน javascript ก็เลยได้มีโอกาสทบทวนหลักการพื้นฐานของมัน
ปกติผมมักจะใช้อย่างเดียว ไม่เคยอ่าน spec หรือศึกษารากฐานของมัน (คิดว่าหลายๆคนก็คงเป็นเช่นนี้เหมือนกัน)

วันนี้จะพูดถึงประเด็นหนึ่งที่น่าสนใจก็คือ เรื่อง new operator

ลองดู code นี้ ที่แสดงการสร้าง object ใหม่ๆด้วย new operator
function Person(name) {
this.name = name;
}

p1 = new Person('pok');

โปรแกรมเมอร์ที่มาจากสาย OOP ทั้งหลายเห็น code นี้แล้วมักจะรู้สึกทะแม่งๆ ตรงที่ว่า
เหตุใด function ธรรมดา ถึงเอาไปสร้าง object ได้
(ใน javascript, function ที่ใช้นำไปสร้าง object เราเรียกมันว่า constructor)

สาเหตุที่เราสงสัยแบบนี้ ก็เพราะว่า paradigm ของเราผูกอยู่กับ โลก OOP แบบ class กับ instance
แต่ใน javascript นั้นโลกของมันไม่มี class, ทุกอย่างในโลกของ javascript คือ Object (มี object อยู่ type เดียวเท่านั้น)
สิ่งที่ต่างกันก็คือ constructor ที่ใช้สร้าง Object นั้นๆ
เช่น date object ก็เกิดจาก constructor ที่ชื่อ Date

เพื่อให้เข้าใจถึง concept constructor เราลองดูขั้นตอนภายในของ new operator บ้างว่า จริงๆแล้วมันทำงานอย่างไร
เริ่มด้วยการ inspect เจ้า p1 ที่สร้างจาก code ข้างบน



ทีนี้เราจะลองสร้าง p2 ที่มี structure เหมือนกับ p1 แต่ไม่ใช้ new operator ในการสร้าง
เริ่มด้วย new Object ธรรมดาขึ้นมาก่อน (อย่างที่บอก ใน javascirpt ทุกอย่างคือ Object ธรรมดาๆ)
p2 = new Object()

ลอง inspect ดู จะเห็นว่า มันคือ object เปล่าๆ ซึ่งมี __proto__ ชี้ไปยัง root object



สิ่งที่เราต้องทำก็คือ เปลี่ยน __proto__ reference ให้ชี้ไปยัง prototype ของ Person
(function ทุก function ใน javascript จะมี property ที่ชื่อ prototype เกิดขึ้นโดยอัตโนมัติ)
p2.__proto__ = Person.prototype;


สุดท้ายก็ทำการเรียกใช้ function Person โดยเปลี่ยน scope ของ this ให้กลายเป็น p2 object ของเรา
Person.apply(p2, ['pok']);


ลอง inspect p2 ดู จะเห็นว่าหน้าตามันเหมือน p1 ที่สร้างจาก new Person(...) แล้ว



Note: เราอาจเรียก function ที่เราใช้กับ new operator ว่า Template function ก็ได้
เพราะหน้าที่มันก็คือการ assign property ให้กับ object เปล่าๆที่ถูกสร้างขึ้นมาโดย new operator

Related link from Roti

2 comments:

Pongneng said...

ทำไมของผม __proto__ มัน link ไปที่ Person อะครับพี่

polawat phetra said...

ลองทำ p2 = new Object หรือยัง ทำเสร็จแล้ว
inspect ดูแล้วมันก็จะชี้ไปที่ Person เหมือนกัน

webkit คงเปลี่ยนวิธีการ present ให้ดูง่ายขึ้นมั้ง