การสร้างเมธอด
ในจาวาสคริปต์นั้น ฟังก์ชันก็ถือเป็นข้อมูลชนิดหนึ่ง
จึงสามารถเป็นพรอเพอร์ตีในออบเจ็กต์ได้
ฟังก์ชันที่ถูกสร้างเป็นพรอเพอร์ตีในออบเจ็กต์มักจะถูกเรียกว่าเมธอด
การสร้างเมธอดนั้น อาจสร้างฟังก์ชันไว้ก่อน แล้วค่อยนำมาใส่ในออบเจ็กต์
หรือจะประกาศสร้างฟังก์ชันภายในออบเจ็กต์เลยก็ได้
ตัวอย่างการสร้างและใช้เมธอด
var maeo = {
chue: "ทามะ",
rongmiao: function() {
alert("เหมียวๆ");
}
};
maeo.rongmiao(); // ได้ เหมียวๆ
อาจสร้างฟังก์ชันไว้ข้างนอกแล้วค่อยป้อนให้
rongmiao = function() {
alert("เหมียวๆ");
};
var maeo = { chue: "ทามะ", rongmiao: rongmiao };
หรือใส่เข้าไปทีหลังเหมือนป้อนค่าพรอเพอร์ตีธรรมดาก็ได้
var maeo = { chue: "ทามะ" };
maeo.rongmiao = function() {
alert("เหมียวๆ");
};
ไม่ว่าจะแบบไหนกทำให้ออบเจ็กต์ meao มีเมธอด rongmiao ที่ใช้งานได้เหมือนกัน
ความแตกต่างระหว่างเมธอดกับฟังก์ชันธรรมดา
จากตัวอย่างการสร้างเมธอดจะเห็นว่าเมธอดก็คือฟังก์ชันธรรมดา
แค่เอามาใส่ไว้ในออบเจ็กต์เท่านั้น
เพียงแต่โดยทั่วไปแล้วสิ่งที่สร้างให้มาเป็นเมธอดนั้นมักจะใช้ทำอะไรที่เกี่ยวข้องกับตัวออบเจ็กต์นั้นโดยตรง
และต่อให้เมธอดนั้นสร้างขึ้นมาจากฟังก์ชันเดียวกัน
แต่ผลที่ได้ก็จะต่างกันไปโดยขึ้นอยู่กับว่าถูกเรียกจากออบเจ็กต์ไหน
ตัวอย่างเช่น เมธอดต่างๆในออบเจ็กต์แถวลำดับ เช่น join
var lukchin = ["๐", "o", "ㅇ"];
var kebab = ["口", "ロ", "ㅁ"];
alert(lukchin.join("-")); // ได้ ๐-o-ㅇ
alert(kebab.join("-")); // ได้ 口-ロ-ㅁ
จะเห็นว่าเมธอดเดียวกัน ใส่อาร์กิวเมนต์เป็น "-" เหมือนกัน
แต่ผลที่ได้จะต่างไป ขึ้นอยู่กับว่าแถวลำดับนั้นบรรจุอะไรไว้อยู่
นั่นเพราะเราสามารถกำหนดให้เมธอดไปเอาข้อมูลภายในออบเจ็กต์มาใช้ได้
ซึ่งข้อมูลในส่วนนี้จะต่างกันไปขึ้นอยู่กับออบเจ็กต์
เพียงแต่ว่าก็มีเมธอดบางชนิดที่ไม่ได้ไปดึงค่าอะไรในออบเจ็กต์มาใช้เลย
เช่นเมธอดต่างๆในออบเจ็กต์ Math (
บทที่ ๑๖) กรณีนี้ออบเจ็กต์ Math
เป็นแค่ออบเจ็กต์ที่ทำหน้าที่เก็บรวมรวมฟังก์ชันไว้เท่านั้น
เมธอดเหล่านี้ก็ไม่ต่างอะไรจากเป็นฟังก์ชันธรรมดา แค่ใส่ไว้ Math
เพื่อสะดวกในการเรียกใช้เท่านั้น
วิธีการที่เมธอดจะใช้ค่าต่างๆภายในออบเจ็กต์ได้นั้น
จะทำโดยผ่านตัวแปรพิเศษที่ชื่อ this
การใช้ this ในเมธอด
this เป็นตัวแปรพิเศษตัวหนึ่งในจาวาสคริปต์
ซึ่งสามารถถูกเรียกใช้จากที่ไหนก็ได้ในโปรแกรมโดยไม่ต้องนิยามมันขึ้นเอง
และไม่สามารถเขียนทับค่า this ได้ด้วย
คำว่า this เป็นภาษาอังกฤษที่มีความหมายว่า "นี่"
ดังนั้นมันจึงเป็นตัวแปรที่ใช้แทน "ตัวเอง" นั่นเอง
ตัวเองในที่นี้หมายถึงออบเจ็กต์ที่เรียกมัน หาก this
ถูกเรียกใช้ในเมธอดของออบเจ็กต์ งั้น this ก็คือตัวแปรที่แทนออบเจ็กต์นั้น
ตัวอย่าง
var thakthai = function() {
alert("สวัสดี ฉันชื่อ" + this.chue);
};
var akari = {
chue: "อาการิ",
thakthai: thakthai
};
var hikari = {
chue: "ฮิการิ",
thakthai: thakthai
};
akari.thakthai(); // ได้ สวัสดี ฉันชื่ออาการิ
hikari.thakthai(); // ได้ สวัสดี ฉันชื่อฮิการิ
จะเห็นว่าเมธอด thakthai ไปดึงเอาพรอเพอร์ตี chue มาใช้ โดยผ่าน this.chue
ดังนั้นต่อให้ออบเจ็กต์ทั้ง ๒ นี้มีเมธอดแบบเดียวกันอยู่
แต่ก็จะแสดงผลไม่เหมือนกัน
this เมื่ออยู่นอกออบเจ็กต์
ดังที่ได้อธิบายไปแล้วว่า this จะแทนออบเจ็กต์ที่เป็นตัวเรียกใช้
แต่ว่าถ้าหากเรียกใช้ this จากด้านนอกออบเจ็กต์ แบบนี้ this ควรจะแทนอะไร?
คำตอบก็คือ this จะแทนออบเจ็กต์ global
global เป็นออบเจ็กต์ที่ห่อหุ้มตัวโปรแกรมทั้งหมด
ปกติแล้วเวลาที่เราประกาศตัวแปรขึ้นมานั้น
จริงๆแล้วถือเป็นการสร้างพรอเพอร์ตีให้กับ global
นั่นหมายความว่าค่าทั้งหมดที่เรียกผ่านตัวแปรนั้นสามารถเรียกโดยผ่านพรอเพอร์ตีของ
this ได้เช่นกัน
var x = 1.1;
alert(this.x); // ได้ 1.1
alert(this.x === x); // ได้ true
เพียงแต่ว่าการเข้าถึงตัวแปรโดยผ่าน this นั้น
หากตัวแปรนั้นไม่ได้ถูกนิยามไว้ก็จะแค่ได้ undefined แต่ถ้าเข้าผ่านตัวแปรโดยตรง
จะเกิดข้อผิดพลาด
alert(this.y); // ได้ undefined
alert(y); // ได้ ReferenceError: y is not defined
กรณีที่รันผ่านเบราว์เซอร์ ออบเจ็กต์ global ก็คือออบเจ็กต์ window แบบนี้ this กับ
window ก็คือสิ่งเดียวกัน อาจเข้าผ่านตัวแปร window ได้
alert(this); // ได้ [object Window]
alert(this === window); // ได้ true
นั่นเพราะ สำหรับเบราว์เซอร์แล้ว
สถานที่ที่รันโปรแกรมก็คือตัวหน้าต่างเบราว์เซอร์นั่นเอง
ให้ระวังว่า this จะแทนตัวออบเจ็กต์เมื่อถูกเรียกผ่านเมธอดเท่านั้น แต่หากใช้
this ในโครงสร้างตอนที่สร้างออบเจ็กต์ แบบนั้น this
ก็ไม่ได้หมายถึงตัวออบเจ็กต์แต่หมายถึงตัว global
ตัวอย่าง
var a = 2;
var obj = {
a: 1,
f: this.a
};
alert(obj.f); // ได้ 2
แบบนี้ this.a จะแทนค่าตัวแปร a คือ 2 ไม่ได้มาแทน obj.a
การเรียกใช้เมธอดด้วย call หรือ apply
ปกติเวลาเรียกใช้ฟังก์ชันหรือเมธอดนั้นจะทำโดยการเติมวงเล็บ () ต่อท้ายไป
แต่นอกจากนี้เมธอดอาจถูกเรียกได้โดยผ่านเมธอดที่ชื่อ call
call เป็นเมธอดที่ติดอยู่ในตัวฟังก์ชัน
เอาไว้ใช้เรียกใช้ฟังก์ชันโดยที่จะมีการเพิ่มอาร์กิวเมนต์ไปอีกตัวเพิ่มจากเดิม
โดยใส่เป็นลำดับแรก อาร์กิวเมนต์ตัวนั้นจะไปแทนตัวแปร this ภายในฟังก์ชันนั้น
เช่นสร้างฟังก์ชันขึ้นมา ให้มีการเรียกตัวแปร this ถ้าเติม ( ) เรียกเฉยๆ this
ก็จะหมายถึงตัว global แต่หากใช้ .call() แล้วใส่ค่าลงไป this ก็จะแทนค่านั้น
var f = function() {
alert(this);
};
f(); // ได้ [object Window]
var a = "นี่";
f.call(a); // ได้ นี่
หากฟังก์ชันนั้นมีพารามิเตอร์ ต้องใส่ค่าต่อจากตัวที่จะให้แทน this
var f = function(x, y) {
alert(this + x + y);
};
f("*", "+"); // ได้ [object Window]*+
var a = "#";
f.call(a, "*", "+"); // ได้ #*+
นอกจากนี้ยังมีเมธอด apply ซึ่งจะคล้ายกับ call
แต่จะรับอาร์กิวเมนต์ที่เหลือนอกจาก this ในรูปของแถวลำดับ
หากใช้ apply แทน call ในตัวอย่างที่แล้วก็จะเขียนแบบนี้
var a = "1";
f.apply(a, ["2", "3"]); // ได้ 123
กรณีที่ call หรือ apply ถูกเรียกในฐานะเมธอดในออบเจ็กต์ก็เช่นเดียวกัน เมื่อใช้
call หรือ apply นั้น this จะแทนอาร์กิวเมนต์ตัวแรกที่ป้อนเข้าไปเสมอ
โดยไม่สนว่าถูกเรียกจากออบเจ็กต์ไหน
ตัวอย่างเช่น มีผู้กล้ากับนักเวทอยู่ นักเวทมีเมธอด (สกิล) ฟื้น HP
var phukla = {
chue: "นิเกะ",
HP: 20
};
var nakwet = {
chue: "คุคุริ",
HP: 12,
fuenHP: function(x) {
this.HP += x;
alert(this.chue + "ได้ฟื้น HP " + x);
}
};
nakwet.fuenHP(10); // ได้ คุคุริได้ฟื้น HP 10
alert(nakwet.HP); // ได้ 22
nakwet.fuenHP.call(phukla, 8); // ได้ นิเกะได้ฟื้น HP 8
alert(phukla.HP); // ได้ 28
(นิเกะ & คุคุริ
ที่มา)
เมื่อเรียกเมธอด fuenHP ที่ตัวนักเวทโดยตรงจะได้ว่า HP ของนักเวทเพิ่ม แต่ถ้าใช้
.call แล้วใส่ออบเจ็กต์ phukla ไป แบบนี้จึงจะเป็นการฟื้น HP ให้ผู้กล้า
จะเห็นว่าตัวแปร this นี้ค่อนข้างพิเศษ จึงต้องระวังเวลาใช้
ต้องรู้ว่าเวลาไหนจะแทนอะไร
เขียนทับเมธอดที่มีอยู่แล้ว
ออบเจ็กต์นั้นแรกเริ่มเมื่อสร้างก็มีเมธอดที่เป็นพื้นฐานติดตัวอยู่แล้ว
ดังเช่นเมธอด toString ดังที่กล่าวถึงไปใน
บทที่ ๕
แต่ว่าเมธอดพวกนี้เป็นสิ่งที่สามารถเขียนทับได้ หากต้องการ
ปกติหากใช้ .toString กับข้อมูลชนิดออบเจ็กต์จะได้ผลเป็น [object Object]
โดยไม่แสดงเนื้อหาข้างในว่ามีอะไรเลย
เวลาที่ใช้ alert
โดยตรงกับออบเจ็กต์จึงไม่ได้ข้อมูลอะไรเกี่ยวกับออบเจ็กต์นั้นเลย
เพื่อให้ออบเจ็กต์สามารถแสดงรายละเอียด เราสามารถกำหนดเมธอด toString ใหม่ได้
โดยเขียนทับลงไป
ตัวอย่าง
var miniryū = {
chue: "มินิริว",
chanit: "มังกร",
sung: 1.8,
namnak: 3.3,
toString: function() {
return (
this.chue +
"\nชนิด: " +
this.chanit +
"\nสูง / หนัก: " +
this.sung +
" เมตร / " +
this.namnak +
" กิโลกรัม"
);
}
};
alert(miniryū);
ได้
มินิริว
ชนิด: มังกร
สูง / หนัก: 1.8 เมตร / 3.3 กิโลกรัม
จะเห็นว่าพอใส่ฟังก์ชันใหม่ลงไปที่พรอเพอร์ตี toString แค่นี้เมื่อใช้ alert
ก็จะแสดงผลตามที่ต้องการได้