ออบเจ็ค ในภาษา JavaScript

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับออบเจ็ค เราจะพูดถึงการประกาศและใช้งานออบเจ็ค และคุณสมบัติที่สำคัญของออบเจ็ค เนื้อหาในบทจะเป็นการสร้างออบเจ็คจาก Object literal หรือ POJO (Plain Old JavaScript Object) ซึ่งเป็นประเภทข้อมูลจากคลาส Object นี่เป็นเนื้อหาในบทนี้

  • การประกาศออบเจ็ค
  • การเข้าถึงค่าในออบเจ็ค
  • Dynamic property
  • Checking property
  • Deleting property
  • Object keys and values
  • Object copying and references
  • Object methods and this keyword

การประกาศออบเจ็ค

ออบเจ็ค (Object) นั้นเป็นประเภทข้อมูลที่เก็บข้อมูลในรูปแบบของ Key และ Value (ที่เรียกว่า Property) โดยที่ Key นั้นจะเป็น String ส่วน Value สามารถเป็นข้อมูลประเภทใดๆ ในภาษา JavaScript; ออบเจ็คนั้นเป็นประเภทข้อมูลจากคลาส Object และเราสามารถสร้างออบเจ็คได้โดยตรงจาก Object literal หรือจากคลาส นี่เป็นรูปแบบการสร้างออบเจ็คในภาษา JavaScript

let object = {
    key1: value1,
    key2: value2,
    ...
};

นี่เป็นการสร้างออบเจ็คในรูปแบบของ Object literal ซึ่งจะใช้วงเล็บ { } และตาม Property ที่ประกอบไปด้วย Key และ Value และถ้าหากออบเจ็คมีหลาย Property เราสามารถคั่นแต่ละค่าด้วยเครื่องหมายคอมมา (,)

let object = new Object();
object.key1 = value1;
object.key2 = value2;
// And so on

อีกรูปแบบหนึ่งก็คือสร้างออบเจ็คจากคลาส Object และกำหนด Property ให้กับออบเจ็คในภายหลัง วิธีนี้ได้ผลลัพธ์เช่นเดียวกัน แต่ในบทเรียนจะใช้แบบ Object literal เป็นหลัก

ต่อไปเป็นตัวอย่างของการประกาศออบเจ็คในภาษา JavaScript เราจะสร้างออบเจ็ค user ซึ่งเป็นออบเจ็คสำหรับเก็บข้อมูลเกี่ยวกับผู้ใช้

let user = {
    id: 1,
    name: "Metin"
};

ในตัวอย่างเป็นการประกาศออบเจ็คและเก็บไว้ในตัวแปร user ในรูปแบบ Object literal ตัวแปรนี้เรียกว่าตัวแปรออบเจ็คหรือ ออบเจ็ค มันประกอบไปด้วยสาม Property สำหรับเก็บข้อมูล ได้แก่ id และ name ซึ่งใช้สำหรับเก็บรหัส และชื่อ ตามลำดับ

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

let user = {
    "id": 1,
    "name": "Metin"
};

ดังนั้นในการประกาศออบเจ็ค คุณสามารถกำหนด Key ออบเจ็คโดยจะใช้ String literal หรือไม่ก็ได้ ถ้าหาไม่ภาษา JavaScript จะแปลงให้เป็น String อัตโนมัติในตอนที่โปรแกรมคอมไพล์

การเข้าถึงค่าในออบเจ็ค

หลังจากที่สร้างออบเจ็คไปแล้ว เราสามารถเข้าถึง Property ของออบเจ็คเพื่ออ่านค่าและเปลี่ยนแปลงค่าได้ด้วยวิธีของ Object notation ในรูปแบบ object.key ในตัวอย่างนี้ เป็นการเข้าถึง Property ในออบเจ็ค user สำหรับอ่านค่าและเปลี่ยนแปลงค่า

access_property.js
let user = {
    id: 1,
    name: "Metin"
};

console.log("ID:", user.id);
console.log("Name:", user.name);

user.name = "Metin M";

console.log("Name:", user.name);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

ID: 1
Name: Metin
Name: Metin M

ออบเจ็ค user นั้นเก็บข้อมูลของผู้ใช้เช่นเดิม แต่ในตอนนี้เป็นการเข้าถึงค่าของ Property และนำมันมาแสดงออกทางหน้าจอ คุณสามารถจินตนาการได้ว่า user.name นั้นเป็นเหมือนตัวแปรหนึ่ง แต่มันแค่อยู่ภายในออบเจ็ค ดังนั้นเราสามารถใช้มันได้เหมือนกับตัวแปรปกติ

user.name = "Metin M";

ในส่วนนี้เป็นเปลี่ยนแปลงค่าของ Property user.name เป็นค่าใหม่ เช่นเดียวกันกับตัวแปรปกติ เราสามารถเปลี่ยนแปลงค่า Property ในออบเจ็คด้วยตัวดำเนินการกำหนดค่า (=)

ค่า Property ของออบเจ็คนั้นไม่จำเป็นต้องเป็นเพียงประเภทข้อมูลพื้นฐาน เช่น ตัวเลข หรือ String เท่านั้น มันสามารถเป็นค่าใดๆ ก็ได้ในภาษา JavaScript เช่น อาเรย์ ฟังก์ชัน หรือแม้แต่ออบเจ็คเอง นี่เป็นตัวอย่าง

mixed_values.js
let mixed = {
    numbers: [1, 2, 3, 4, 5],
    sum: function (a, b) {
        return a + b;
    },
    user: {
        id: 1,
        name: "Metin"
    }
};

console.log(mixed);

console.log(mixed.numbers);
console.log(mixed.sum(10, 20));
console.log(mixed.user.name);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{
  numbers: [ 1, 2, 3, 4, 5 ],
  sum: [Function: sum],
  user: { id: 1, name: 'Metin' }
}
[ 1, 2, 3, 4, 5 ]
30
Metin

ตัวแปรออบเจ็ค mixed นั้นเก็บข้อมูลประเภทต่างๆ ที่สามารถใช้งานได้ในภาษา JavaScript โดย numbers นั้นเป็นอาเรย์ของตัวเลข sum เป็นฟังก์ชันสำหรับบวกเลข และ user เป็นออบเจ็คที่ซ้อนอยู่ในออบเจ็คอีกที จะเห็นว่าทุกอย่างที่เราสามารถกำหนดให้กับตัวแปรนั้นสามารถกำหนดให้กับ Property ของออบเจ็คได้เช่นกัน

console.log(mixed.numbers);
console.log(mixed.sum(10, 20));
console.log(mixed.user.name);

จากนั้นเราสามารถเข้าถึงค่าในออบเจ็คผ่าน Property ของมัน ในกรณีนี้เนื่องจาก sum นั้นเป็นฟังก์ชัน นั่นทำให้เราสามารถเรียกใช้มันด้วยคำสั่ง mixed.sum(10, 20) หรือการเข้าถึงชื่อที่ซ้อนอยู่ในออบเจ็คด้วย mixed.user.name

นอกจากนี้ Property ของออบเจ็คยังสามารถกำหนดหลังจากที่ประกาศไปแล้วได้ นี่มีประโยชน์ในกรณีที่เราไม่ทราบล่วงหน้าว่าออบเจ็คจะมี Property อะไรบ้าง ยกตัวอย่างเช่น

define_property.js
let song = {};

song.name = "Good Guys";
song.artist = "LANY";
song.year = 2020;

console.log(song);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{ name: 'Good Guys', artist: 'LANY', year: 2020 }

ในตอนแรกเราสร้างออบเจ็คว่าง song จากนั้นเพิ่มสาม Property เข้ามาในภายหลัง จะเห็นว่าผลลัพธ์ที่ได้ไม่แตกต่างกับกำหนดในรูปแบบ Object literal แต่นี่ช่วยให้เราสามารถเพิ่ม Property เข้ามาเพิ่มจากออบเจ็คตั้งต้นได้

ในตัวอย่างที่ผ่านมา เป็นการเข้าถึงค่าในออบเจ็คในรูปแบบ object.key ซึ่งการเข้าถึงดังกล่าวเป็นการเข้าถึงแบบ Object notation อย่างไรก็ตาม ในภาษา JavaScript นั้นมีอีกวิธีที่เราสามารถเข้าถึงค่าในออบเจ็คได้ นั่นคือการเข้าถึงในรูปแบบของ Array like ซึ่งมีรูปแบบเป็น object[key]

access_property2.js
let fruits = {
    apple: 3,
    banana: 5
};

fruits["banana"] = 10;
console.log(fruits.banana);

console.log(fruits.apple);
console.log(fruits["apple"]);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

10
3
3

ในตัวอย่างเป็นการเข้าถึง Property ของออบเจ็คทั้งในรูปแบบ object.key และ object[key] สำหรับในแบบหลังนั้น คีย์ต้องกำหนดเป็น String เสมอ นั่นเป็นเพราะว่าในการทำงานเบื้องหลังภาษา JavaScript เก็บคีย์ของออบเจ็คเป็น String

และเช่นเดียวกัน เราสามารถใช้ String literal ในการกำหนด Key ให้กับออบเจ็คในตอนที่มันถูกประกาศได้ ในการใช้ String เพื่อกำหนด Key ให้กับออบเจ็คจะทำให้เราสามารถใช้ตัวอักษรพิเศษ และสร้างคีย์แบบไดนามิกส์ได้ นี่เป็นตัวอย่าง

string_literal_keys.js
let scores = {
    "matteo marcus": 80,
    "chris burden": 70,
    "metin.m": 50
};

console.log(scores);
console.log(scores["matteo marcus"]);
console.log(scores["chris burden"]);
console.log(scores["metin.m"]);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{ 'matteo marcus': 80, 'chris burden': 70, 'metin.m': 50 }
80
70
50

ในตัวอย่างนี้ เนื่องจากเรากำหนดคีย์ของออบเจ็คด้วย String นั่นทำให้เราสามารถใช้เว้นวรรคหรือเครื่องหมายจุด (.) เป็นคีย์ได้ อย่างไรก็ตามในการเข้าถึงค่าของ Property ที่มีคีย์ที่ประกอบไปด้วยตัวอักษรพิเศษ มันจะต้องถูกเข้าถึงในรูปแบบ object[key] เสมอ

เหตุผลนั้นเรียบง่าย นั้นเป็นเพราะว่าภายนอก Object literal ภาษา JavaScript ใช้เว้นวรรคและตัวอักษรพิเศษอื่นๆ เป็นตัวกำหนดไวยากรณ์ของภาษา ยกตัวอย่างเช่น

scores.matteo marcus    // Syntax error, two statements but no ;
scores.metin.m          // Access m in scores.metin

นั่นจะทำให้โปรแกรมมองว่าคำสั่งที่คั่นด้วยช่องว่างเป็นคนละทำสั่งกันและทำให้เกิดข้อผิดพลาดขึ้น สำหรับในคำสั่งทีสองโปรแกรมมองว่าเป็นการเข้าถึง Property m ในออบเจ็ค score.metin ซึ่งไม่มีอยู่

และนี่ก็เป็นพื้นฐานของการประกาศและใช้งานออบเจ็คในเบื้องต้น ต่อไปจะเป็นการศึกษาเกี่ยวกับคุณสมบัติอื่นๆ ของออบเจ็ค มาดูกันว่าเราสามารถทำอะไรได้บ้างกับ Property ของออบเจ็คในภาษา JavaScript

Dynamic property

Dynamic property ช่วยให้เราสามารถกำหนด Key ของออบเจ็คจากค่าในตัวแปรหรือค่าที่ได้จากการคำนวณได้ในรูปแบบ [exp] มันมีประโยชน์ในกรณีที่เราต้องการสร้าง Key จากค่าที่อาจจะได้มาในขณะที่โปรแกรมทำงาน นี่เป็นตัวอย่าง

dynamic_property.js
let computed = "a";

let object = {
    [computed]: 1,
    ["hello".toUpperCase()]: 2
};

console.log(object);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{ a: 1, HELLO: 2 }

ในตัวอย่างนี้ เป็นการประกาศออบเจ็คโดยการกำหนด Key แบบไดนามิกส์ ซึ่ง Key นั้นจะกำหนดในวงเล็บในรูปแบบ [exp] โดยที่ exp สามารถเป็นนิพจน์ใดๆ ในภาษา JavaScript เช่น ตัวแปร ค่าที่ได้จากการคำนวณ หรือการเรียกใช้เมธอด เป็นต้น

let computed = "a";

ลองจินตนาการว่าค่าในตัวแปร computed สามารถเป็นค่าที่รับมาจากผู้ใช้หรือเป็นชื่อฟิลด์ที่ได้มาจากฐานข้อมูล นี่จะทำให้เราสามารถสร้าง Property แบบไดนามิส์จากค่าที่มีในตอนที่โปรแกรมทำงานได้โดยที่ไม่จำเป็นต้องทราบล่วงหน้า

ในตัวอย่างก่อนหน้าเราได้กำหนด Property แบบไดนามิส์ให้ตอนที่ออบเจ็คถูกสร้าง ในกรณีที่ออบเจ็คถูกสร้างไปแล้ว เราสามารถเข้าถึงค่า Property แบบไดนามิส์ได้ในรูปแบบ object[exp] โดยที่ Key นั้นสามารถเป็น String literal หรือค่าอื่นๆ ที่ถูกสร้างขึ้นในขณะที่โปรแกรมทำงาน มาดูตัวอย่าง

dynamic_property2.js
let htmlTags = ["strong", "em", "sup", "sub", "ins", "code"];

let tags = {};
for (let tag of htmlTags) {
    tags[tag] = tag.length;
}

console.log(tags);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{ strong: 6, em: 2, sup: 3, sub: 3, ins: 3, code: 4 }

สิ่งที่แตกต่างจากตัวอย่างก่อนหน้าก็คือในตัวอย่างนี้ เป็นการกำหนด Property แบบไดนามิส์ หลังจากที่ออบเจ็คถูกสร้างไปแล้ว เรามีตัวแปรอาเรย์ htmlTags ที่เก็บชื่อแท็กของ HTML จากนั้นใช้คำสั่ง for loop เพื่อวนรอบสมาชิกในอาเรย์เพื่อนำมาสร้างออบเจ็ค โดยใช้ Key เป็นชื่อของแท็กและความยาวของแท็กเป็นค่าของ Property

ไดนามิกส์ Property มีประโยชน์มากในการเขียนโปรแกรม เนื่องจากมันถูกสร้างขึ้นในตอนที่โปรแกรมทำงาน นั่นทำให้เราไม่จำเป็นต้องทราบว่า Property ในออบเจ็คจะต้องมีอะไรบ้าง ในตัวอย่างต่อไปนี้เป็นโปรแกรมสำหรับนับผลไม้ในอาเรย์ โดยใช้ชื่อของผลไม้เป็น Key ของออบเจ็คเพื่อนับข้อมูล นี่เป็นตัวอย่าง

counting_fruits.js
let fruits = [
    "Apple", "Banana", "Apple", "Orange", "Apple", "Grape", "Banana"
];
let counter = {};

for (let fruit of fruits) {
    if (typeof counter[fruit] === 'undefined') {
        counter[fruit] = 1;
    } else {
        counter[fruit]++;
    }
}

console.log(counter);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

{ Apple: 3, Banana: 2, Orange: 1, Grape: 1 }

อาเรย์ fruits นั้นเป็นอาเรย์ที่เก็บชื่อของผลไม้ ซึ่งผลไม้แต่ละชนิดอาจมีได้มากกว่าหนึ่งครั้งในอาเรย์ เราต้องการทราบว่าผลไม้แต่ละชนิดในอาเรย์นั้นมีจำนวนเท่าไหร่ ดังนั้นเราจึงเขียนโปรแกรมมานับโดยใช้ความสามารถของไดนามิกส์ Property ของออบเจ็ค

let counter = {};

เราได้สร้างออบเจ็คว่าง counter สำหรับนับผลไม้ในอาเรย์ ออบเจ็คนี้จะถูกเพิ่ม Key เข้ามาในภายหลัง จากนั้นใช้คำสั่ง for loop เพื่อวนอ่านค่าผลไม้ในอาเรย์สำหรับการนับ

if (typeof counter[fruit] === 'undefined') {
    counter[fruit] = 1;
} else {
    counter[fruit]++;
}

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

console.log(counter);

และในตอนท้ายในตัวแปรออบเจ็ค counter จะเป็นออบเจ็คที่ได้จากการนับผลไม้ในอาเรย์ โดยมีชื่อของผลไม้เป็น Key ของจำนวนที่นับได้เป็นค่าของ Property นั้นๆ และเราได้แสดงมันออกมาทางหน้าจอ

Checking property

ในภาษา JavaScript การเข้าถึง Property ที่ไม่มีอยู่บนออบเจ็คนั้นจะไม่เกิดข้อผิดพลาด แต่จะได้ค่าเป็น undefined ในบางครั้งเราอาจต้องการตรวจสอบว่า Property มีอยู่บนออบเจ็คหรือไม่ ดังนั้นเราสามารถทำเช่นนั้นได้โดยการตรวจสอบว่ามันเป็น undefined หรือไม่โดยการใช้ตัวดำเนินการ typeof นี่เป็นตัวอย่าง

checking_property.js
let user = {
    id: 1,
    name: "Name"
};

if (typeof user.lang === "undefined") {
    user.lang = "JavaScript";
    console.log("Property lang is defined");
}

console.log(user);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Property lang is defined
{ id: 1, name: 'Name', lang: 'JavaScript' }

ในตัวอย่างเป็นการตรวจสอบว่าออบเจ็ค user มี Property lang อยู่หรือไม่ด้วยตัวดำเนินการ typeof ซึ่งตัวดำเนินการนี้ส่งค่ากลับเป็นประเภทของข้อมูลในรูปแบบของ String ในกรณีนี้คือ "undefined" เมื่อไม่มี Property อยู่บนออบเจ็ค หากยังไม่มีเรากำหนดค่าให้กับ Property และแสดงค่าของออบเจ็คออกทางหน้าจอ

แม้ว่าเราจะสามารถใช้คำสั่ง if เพื่อเปรียบเทียบกับค่าของ undefined หรือใช้ Property เป็นเงื่อนไขได้โดยตรง ยกตัวอย่างเช่น

if (user.lang === undefined) {
// Or
if (user.lang) {

แต่วิธีนี้ไม่แนะนำเนื่องจากเราไม่ควรเข้าถึงค่าที่เป็น undefined โดยตรงเพราะมันสามารถทำให้โค้ดเกิดความผิดพลาดได้ง่าย การใช้ตัวดำเนินการ typeof จะทำให้โค้ดชัดเจนกว่าว่ามันกำลังทำงานอะไร

Deleting property

ตัวดำเนินการ delete นั้นใช้สำหรับลบ Property ออกจากออบเจ็คในกรณีที่เราไม่ต้องการให้มันมีอยู่อีกต่อไป นี่เป็นตัวอย่าง

deleting_property.js
let user = {
    id: 1,
    name: "Name",
    salary: 55000
};

console.log("Before delete");
console.log(user);

delete user.salary;

console.log("After delete");
console.log(user);
console.log(user.salary);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Before delete
{ id: 1, name: 'Name', salary: 55000 }
After delete
{ id: 1, name: 'Name' }
undefined

ในตัวอย่างนี้เรามีตัวแปรออบเจ็ค user ที่ประกอบไปด้วยสาม Property และในตอนนี้เราต้องการลบ Property salary ออกไปจากออบเจ็ค

delete user.salary;

เราสามารถใช้ตัวดำเนินการ delete ตามด้วยออบเจ็ค Property เพื่อลบมันออกไปจากออบเจ็ค นั่นจะทำให้ Property นี้ไม่มีอยู่ในออบเจ็คอีกต่อไปและมีค่าเป็น undefined เหมือนกับ Property ที่ไม่มีอยู่เมื่อเราพยายามเข้าถึงมัน

Object keys and values

ในการทำงานกับออบเจ็คเราอาจต้องการอ่านค่า Key และ Value ทั้งหมดของออบเจ็ค ในภาษา JavaScript มีสองเมธอดที่ให้เราทำเช่นนี้ได้ เมธอด Object.keys ส่งค่ากลับเป็นอาเรย์ของ Key ทั้งหมดในออบเจ็ค และเมธอด Object.values ส่งค่ากลับเป็น Value ทั้งหมดในออบเจ็ค นี่เป็นตัวอย่างการใช้งาน

keys_values.js
let site = {
    name: "marcuscode",
    year: 2020,
    visibility: true
};

console.log(Object.keys(site));
console.log(Object.values(site));

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

[ 'name', 'year', 'visibility' ]
[ 'marcuscode', 2020, true ]

ในตัวอย่าง เป็นการใช้งานเมธอด Object.keys และเมธอด Object.values เพื่อรับเอา Key และ Value ทั้งหมดของออบเจ็ค site ตามลำดับ โดยค่าที่ส่งกลับมานั้นจะเป็นอาเรย์ที่มีการเรียงลำดับเหมือนกับตอนที่มันถูกกำหนดในออบเจ็ค

นอกจากนี้ เรายังสามารถใช้คำสั่ง for in สำหรับวนอ่านค่า Key ภายในออบเจ็คได้ นี่เป็นตัวอย่าง

loop_through_keys.js
let site = {
    name: "marcuscode",
    year: 2020,
    visibility: true
};

console.log("KEY\tVALUE");
for (let key in site) {
    console.log(key + "\t" + site[key]);
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

KEY     VALUE
name    marcuscode
year    2020
visibility      true

คำสั่ง for in ส่งค่ากลับเป็น Key ของอาเรย์ในแต่ละรอบของการวนมาเก็บไว้ในตัวแปร key จากนั้นเราสามารถใช้ Key ในการเข้าถึงค่า Property ด้วย site[key] ในการใช้วิธีนี้จะทำให้เราสามารถจัดการสิ่งต่างๆ ที่ต้องการได้ภายในคำสั่ง for เช่นกำหนดเงื่อนไขบางก่อนเข้าถึง Property เป็นต้น

Object copying and references

การเก็บข้อมูลของออบเจ็คในหน่วยความจำนั้นแตกต่างกับข้อมูลพื้นฐาน เช่น ตัวเลข หรือ String ดังนั้นในตัวอย่างต่อไปนี้เราจะพูดเกี่ยวกับว่าออบเจ็คเก็บข้อมูลอย่างไร และการคัดลอกออบเจ็คในภาษา JavaScript

Object references

ออบเจ็คมีรูปแบบการเก็บข้อมูลที่แตกต่างกับประเภทข้อมูลพื้นฐาน (Primitive types) เมื่อเราสร้างออบเจ็คและเก็บไว้ในตัวแปร ค่าที่เก็บในตัวแปรจะเป็นการอ้างอิง (Reference) ถึึงออบเจ็คนั้น แทนที่จะเป็นค่าจริงๆ ของออบเจ็ค ยกตัวอย่างเช่น

object_references.js
let box1 = {
    width: 50,
    height: 50
};

let box2 = box1;

box2.width = 100;

console.log("box1:", box1);
console.log("box2:", box2);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

box1: { width: 100, height: 50 }
box2: { width: 100, height: 50 }

ในตัวอย่างเราได้สร้างออบเจ็ค box1 ที่มีสอง Property สำหรับเก็บยาวกว้างและความสูงของกล่อง ในตอนที่เรากำหนดออบเจ็คให้กับตัวแปร ค่าอ้างอิงไปยังออบเจ็คจะถูกเก็บไว้ในตัวแปรแทน ไม่ใช่ค่าทั้งหมดของออบเจ็ค

let box2 = box1;

จากนั้นเราประกาศตัวแปร box2 และกำหนดค่าให้มันเท่ากับตัวแปร box1 นั่นทำให้ตัวแปรทั้งสองเก็บค่าอ้างอิงเดียวกัน และทำให้อ้างถึงออบเจ็คเดียวกัน หรือสรุปง่ายๆ ก็คือสองตัวแปรนี้เป็นเหมือนออบเจ็คเดียวกันนั่นเอง

box2.width = 100;

จากนั้นเราเปลี่ยนความยาวของกล่องเป็น 100 ผ่านตัวแปร box2 นั่นจะทำให้ในการเข้าถึงออบเจ็คในทุกทีี่จะเปลี่ยนไปด้วย ดังนั้นเมื่อแสดงค่าออบเจ็คจากตัวแปรทั้งสองออกมา มันเปลี่ยนไปทั้งหมดเนื่องจากมันเป็นออบเจ็คเดียวกันนั่นเอง

จากการทำงานในตัวอย่างสามารถแสดงเป็นรูปภาพได้ดังนี้

box2 <- box1 <- #reference -> { width: 100, height: 100}

ตัวแปร box1 เก็บค่าที่อ้างอิงไปยังออบเจ็คของกล่อง จากนั้นเรากำหนดให้ตัวแปรตัวแปร box2 อ้างอิงไปยังออบเจ็คเดียวกัน หรือกล่าวอีกนัยหนึ่ง ตัวแปรทั้งสองเป็นเพียงทางผ่านไปยังออบเจ็คนั่นเอง

ซึ่งพฤติกรรมนี้ส่งผลเช่นเดียวกับตอนที่เราส่งออบเจ็คเป็นพารามิเตอร์ของฟังก์ชัน ตัวแปรพารามิเตอร์ที่ประกาศในฟังก์ชันจะอ้างถึงออบเจ็คเดียวกันกับออบเจ็คภายนอก นี่เป็นตัวอย่าง

object_references2.js
function info(u) {
    // Increase salary by 10%
    u.salary *= 1.1;
    console.log(`${u.name}'s salary is ${u.salary}`);
}

let user = {
    id: 1,
    name: "Metin",
    salary: 58000
};

info(user);
console.log("After function calls");
console.log(user);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Metin's salary is 63800.00000000001
After function calls
{ id: 1, name: 'Metin', salary: 63800.00000000001 }

ในตัวอย่าง เรามีตัวแปรออบเจ็ค user ที่เก็บรหัส ชื่อ และข้อมูลเงินเดือนของผู้ใช้ และฟังก์ชัน info สำหรับแสดงข้อมูลเงินเดือนออกทางหน้าจอ

function info(u) {
    // Increase salary by 10%
    u.salary *= 1.1;
    console.log(`${u.name}'s salary is ${u.salary}`);
}

เมื่อเรียกใช้ฟังก์ชัน info(user) ภาษา JavaScript จะส่งค่าอ้างอิงของออบเจ็คไปยังพารามิเตอร์ u ของฟังก์ชันด้วยการทำงานที่คล้ายกับคำสั่งต่อไปนี้

u = user;

นั่นทำให้อะไรก็ตามที่เราทำการเปลี่ยนแปลงกับตัวแปร u ในฟังก์ชันจะส่งผลต่อตัวแปร user นอกฟังก์ชัน และเมื่อเราแสดงค่าในออบเจ็ค user หลังจากเรียกใช้ฟังก์ชันจะเห็นว่าค่า salary ในตัวแปร user ก็เปลี่ยนไปเช่นกัน

Object copying

การพยายามคัดลอกออบเจ็คด้วยตัวดำเนินการกำหนดค่า = ในตัวอย่างก่อนหน้านั้นเหมือนจะไม่ได้ผล เพราะนั่นไม่ใช่การคัดลอก แต่เป็นการสร้างตัวแปรใหม่เพื่อให้อ้างถึงออบเจ็คเดียวกันแทน

ในบางครั้ง เราอาจต้องการคัดลอกออบเจ็คที่มีอยู่เป็นออบเจ็คใหม่ และทำให้ออบเจ็คทั้งสองเป็นคนละออบเจ็คกันและไม่ขึ้นต่อกัน เราเรียกวิธีการนี้ว่า Object copying หรือ Object cloning; ในภาษา JavaScript เราสามารถคัดลอกออบเจ็คด้วยเมธอด Object.assign นี่เป็นตัวอย่าง

object_copying.js
let user1 = {
    id: 1,
    name: "Metin",
    salary: 58000,
    isAdmin: true
};

let user2 = {};
Object.assign(user2, user1);

user2.id = 2;
user2.name = "Chris";

console.log("user1:", user1);
console.log("user2:", user2);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

user1: { id: 1, name: 'Metin', salary: 58000, isAdmin: true }
user2: { id: 2, name: 'Chris', salary: 58000, isAdmin: true }

ในตัวอย่าง เรามีตัวแปรออบเจ็ค user1 ซึ่งมีสี่ Property สำหรับเก็บข้อมูลของผู้ใช้ ในตอนนี้เราต้องการคัดลอกค่าทั้งหมดจากออบเจ็คดังกล่าวมาเก็บไว้ในตัวแปรใหม่

let user2 = {};
Object.assign(user2, user1);

เพื่อทำเช่นนั้น เราสามารถใช้เมธอด Object.assign ในการคัดลอกรายละเอียดทั้งหมดบนออบเจ็ค user1 ไปยังออบเจ็ค user2 ได้ ในตอนนี้ออบเจ็คทั้งสองเป็นคนละออบเจ็คกัน เราสามารถใช้มันได้อย่างเป็นอิสระจากกัน

user2.id = 2;
user2.name = "Chris";

จากนั้นเราเปลี่ยนรหัสและชื่อของออบเจ็ค user2 เป็นค่าใหม่โดยยังคงเหลืออีกสอง Property ที่เหลือไว้เหมือนเดิม จะเห็นว่าการคัดลอกออบเจ็คนั้นทำให้เราไม่ต้องกำหนด Property สำหรับออบเจ็ค user2 ทั้งหมดใหม่ตั้งแต่ต้น

console.log("user1:", user1);
console.log("user2:", user2);

และเมื่อเราแสดงข้อมูลของออบเจ็คออกทางหน้าจอ ข้อมูลในออบเจ็คนั้นแตกต่างกัน เนื่องจากมันเป็นคนละออบเจ็คนั่นเอง

หมายเหตุ: เมธอด Object.assign ทำการคัดลอก Property ของออบเจ็คเพียงชั้นเดียวเท่านั้น ในกรณีที่ Property เก็บค่าเป็นออบเจ็คที่ซ้อนกัน เราจะต้องเขียนโปรแกรมสำหรับคัดลอกมันด้วยตัวเอง

Object methods and this keyword

ในตัวอย่างก่อนหน้าทั้งหมด เราใช้ออบเจ็คเพื่อเก็บข้อมูลประเภทต่างๆ โดยใช้ข้อมูลเหล่านั้นเหมือนกับว่ามันเป็นเพียงตัวแปรทั่วไปเท่านั้น ในตัวอย่างนี่เราจะใช้งานออบเจ็คเพื่อจัดการกับสถานะ (Property) ภายในตัวมันเองโดยการใช้งานคำสั่ง this เพื่ออ้างถึง Property อื่นภายในออบเจ็คเดียวกัน

ในตัวอย่างนี้เป็นโปรแกรมสำหรับหาพื้นที่ของออบเจ็ค โดยการใช้ความสามารถของออบเจ็คในภาษา JavaScript

circle.js
let circle = {
    radius: 5,
    area: function () {
        return (this.radius ** 2) * Math.PI;
    }
};

console.log("Radius:", circle.radius);
console.log("Area:", circle.area());

circle.radius = 10;
console.log("Radius:", circle.radius);
console.log("Area:", circle.area());

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Radius: 5
Area: 78.53981633974483
Radius: 10
Area: 314.1592653589793

ตัวแปรออบเจ็ค circle นั้นมีสอง Property โดย radius นั้นเก็บค่ารัศมีของวงกลม และฟังก์ชัน area สำหรับคำนวณหาพื้นที่จากรัศมีดังกล่าว

return (this.radius ** 2) * Math.PI;

ในฟังก์ชัน area นั้นเป็นการคำนวณหาพื้นที่ของวงกลมจากสูตรการหาพื้นที่ และในการเข้าถึงรัศมีของวงกลมด้วยคำสั่ง this.radius นั้นเป็นการเข้าถึงรัศมีของออบเจ็คปัจจุบันซึ่งก็คือ circle นั่นเอง

circle.radius = 10;
console.log("Radius:", circle.radius);
console.log("Area:", circle.area());

จากนั้นเปลี่ยนค่ารัศมีของวงกลมเป็น 10 และเรียกใช้งานฟังก์ชัน area อีกครั้ง จะเห็นว่าค่ารัศมีดังกล่าวนั้นได้ถูกนำมาใช้ในการคำนวณหาพื้นที่แทน เนื่องจากว่ามันเป็นค่ารัศมีปัจจุบันที่ออบเจ็ค circle เก็บอยู่

กล่าวโดยสรุปก็คือฟังก์ชันภายในออบเจ็คสามารถเข้าถึง Property บนออบเจ็คเดียวกันได้ด้วยคำสั่ง this ตามด้วยชื่อของ Property ซึ่งนี่สามารถใช้เรียกฟังก์ชันอื่นที่อยู่บนออบเจ็คเดียวกันได้เช่นกัน

ในตัวอย่างนี้แสดงให้เห็นถึงแนวคิดพื้นฐานในการเขียนโปรแกรมเชิงวัตถุ (OOP) โดยที่ออบเจ็คสามารถมี Property เพื่อเก็บข้อมูลและเมธอดสำหรับจัดการกับข้อมูลภายในออบเจ็คเอง แต่เราไม่ได้ครอบคลุมเกี่ยวกับ OOP ในบทนี้ เนื้อหาในส่วนนี้เพื่อให้คุณเข้าใจเกี่ยวกับการใช้งานคำสั่ง this เท่านั้น

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