φυβλαςのβλογ
บล็อกของ phyblas



javascript เบื้องต้น บทที่ ๑๙: การสร้างเมธอดให้ออบเจ็กต์
เขียนเมื่อ 2019/07/31 23:30
แก้ไขล่าสุด 2021/09/28 16:42


การสร้างเมธอด

ในจาวาสคริปต์นั้น ฟังก์ชันก็ถือเป็นข้อมูลชนิดหนึ่ง จึงสามารถเป็นพรอเพอร์ตีในออบเจ็กต์ได้

ฟังก์ชันที่ถูกสร้างเป็นพรอเพอร์ตีในออบเจ็กต์มักจะถูกเรียกว่าเมธอด

การสร้างเมธอดนั้น อาจสร้างฟังก์ชันไว้ก่อน แล้วค่อยนำมาใส่ในออบเจ็กต์ หรือจะประกาศสร้างฟังก์ชันภายในออบเจ็กต์เลยก็ได้

ตัวอย่างการสร้างและใช้เมธอด
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 ก็จะแสดงผลตามที่ต้องการได้




-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> javascript

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความล่าสุด

นั่งรถไฟตามสายอิชิโนมากิมาลงที่สถานีทากางิโจวเมืองมัตสึชิมะเปลี่ยนรถไฟไปยังสายหลักโทวโฮกุ
โนบิรุ ซากสถานีรถไฟเก่าและสวนอธิษฐานฟื้นฟูภัยพิบัติแผ่นดินไหวครั้งใหญ่ในญี่ปุ่นตะวันออกเมืองฮิงาชิมัตสึชิมะ
เดินเล่นชมนกนางนวลแถวลานกว้างริมฝั่งทะเลเมืองโอนางาวะ ดูซากป้อมยามเก่าที่ถูกทำลายจากคลื่นทสึนามิ แล้วนั่งรถไฟกลับจากสถานีโอนางาวะ
ซีพัลเพียร์โอนางาวะ ณ เมืองเล็กๆริมชายฝั่งอ่าวสุดทางรถไฟสายอิชิโนมากิซึ่งฟื้นฟูขึ้นหลังเหตุการณ์คลื่นทสึนามิ
การทำให้สายอักขระใน dart สามารถแปลงข้อความแบบ sprintf ได้เหมือนใน python หรือ ruby

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文