Static method and Static property ในภาษา JavaScript

22 February 2022

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับ Static method และ Static property ในภาษา JavaScript ซึ่งเป็นสมาชิกแบบคงที่ของคลาสโดยมันสามารถเรียกใช้งานได้จากชื่อของคลาสโดยตรง และจะไม่เป็นส่วนหนึ่งของออบเจ็คที่สร้างมาจากคลาส (Instance members) นี่เป็นเนื้อหาในบทนี้

  • Static methods
  • Static properties
  • Static setter and getter

Static methods

Static method เป็นเมธอดที่ประกาศในคลาสโดยมีคำสั่ง static ระบุที่หน้าชื่อของเมธอด ซึ่งทำให้มันเป็นเมธอดแบบคงที่ของคลาส โดยที่ Static method จะไม่เป็นส่วนหนึ่งของออบเจ็คที่สร้างมาจากคลาสที่ประกาศมัน นี่เป็นตัวอย่างของการประกาศและใช้งาน Static method ในภาษา JavaScript

rectangle.js
class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }

    getArea() {
        return this.width * this.height;
    }

    static showInfo(rect) {
        console.log("Width: " + rect.width);
        console.log("Height: " + rect.height);
        console.log("Area: " + rect.getArea());
    }
}

let rect1 = new Rectangle(5, 3);
let rect2 = new Rectangle(2, 4);

// Using static methods
console.log("Info about rect1");
Rectangle.showInfo(rect1);

console.log("Info about rect2");
Rectangle.showInfo(rect2);

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

Info about rect1
Width: 5
Height: 3
Area: 15
Info about rect2
Width: 2
Height: 4
Area: 8

ในตัวอย่างนี้ เราได้สร้างคลาส Rectangle ที่มีสอง Property คือ width และ height สำหรับเก็บความยาวและความสูงของรูปสี่เหลี่ยมตามลำดับ และหนึ่งเมธอด getArea สำหรับคำนวณหาพื้นที่ของรูปสี่เหลี่ยม โดยเหล่านี้เป็นการประกาศสมาชิกในรูปแบบปกติของคลาสที่เรียกว่า Instance property และ Instance method

static showInfo(rect) {
    console.log("Width: " + rect.width);
    console.log("Height: " + rect.height);
    console.log("Area: " + rect.getArea());
}

จากนั้นเราได้ประกาศเมธอด showInfo ที่เป็นเมธอดแบบ Static ที่ใช้เพื่อแสดงข้อมูลเกี่ยวกับออบเจ็คที่สร้างมาจากคลาสเดียวกัน Rectangle ในกรณีนี้ เมธอด showInfo ทำหน้าที่เป็นเหมือนเมธอดอำนวยความสะดวกที่มีการทำงานเกี่ยวข้องกับออบเจ็คคลาส

Rectangle.showInfo(rect1);
Rectangle.showInfo(rect2);

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

นอกจากนี้ Static เมธอดยังมักจะถูกใช้เพื่อรวมกลุ่มเมธอดที่มีการทำงานคล้ายกันเข้าด้วยกัน ยกตัวอย่างเช่น เราต้องการสร้างหลายฟังก์ชันเพื่อแสดง Log ดังนั้นเราสามารถเก็บมันไว้ในคลาสเดียวกันโดยประกาศเป็น Static เมธอดได้ นี่เป็นตัวอย่าง

logging.js
class Logging {
    static verbose(message) {
        console.log(`[VERBOSE] > ${message}`);
    }

    static info(message) {
        console.log(`[INFO] > ${message}`);
    }

    static warn(message) {
        console.log(`[WARNING] > ${message}`);
    }

    static error(message) {
        console.error(`[ERROR] > ${message}`);
    }
}

Logging.verbose("This is my log message.");
Logging.error("Oops! There was an error occurred!");

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

[VERBOSE] > This is my log message.
[ERROR] > Oops! There was an error occurred!

ในตัวอย่างนี้ จะเห็นว่าคลาส Logging ประกอบไปด้วยเพียง Static เมธอดที่ใช้สำหรับแสดง Log ในระดับต่างๆ ออกทางหน้าจอเท่านั้น เนื่องจากมันไม่มี Instance property และ Instance method ดังนั้นมันไม่มีประโยชน์ในการนำไปสร้างออบเจ็ค และนี่ทำให้มันเป็นเพียงคลาสช่วยอำนวยความสะดวกเกี่ยวกับการแสดง Log เท่านั้น

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

Static properties

Static property เป็นตัวแปรที่ประกาศภายในคลาสโดยระบุคำสั่ง static ที่หน้าชื่อของตัวแปร นี่จะทำให้ตัวแปรขึ้นอยู่กับคลาสและไม่ได้เป็นส่วนหนึ่งของออบเจ็ค (Instance property) มันมักจะใช้เพื่อเก็บข้อมูลบางอย่างที่เกี่ยวข้องกับคลาส มาดูตัวอย่างการประกาศและใช้งาน Static property ในภาษา JavaScript

book.js
class Book {
    static count = 0;

    constructor(title, author) {
        this.title = title;
        this.author = author;

        Book.count++;
    }

    info() {
        console.log(`- ${this.title} by ${this.author}`);
    }
}

let b1 = new Book("Great Circle", "Maggie Shipstead");
let b2 = new Book("The Prophets", "Robert Jones");
let b3 = new Book("My Monticello", "Jocelyn Nicole Johnson");

console.log("My favorite books");
b1.info();
b2.info();
b3.info();
console.log(`Total books created: ${Book.count}`);

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

My favorite books
- Great Circle by Maggie Shipstead
- The Prophets by Robert Jones
- My Monticello by Jocelyn Nicole Johnson
Total books created: 3

ในตัวอย่างนี้ เราได้สร้างคลาส Book ซึ่งเป็นคลาสของหนังสือที่มีสอง Property คือ title และ author สำหรับเก็บชื่อและชื่อของผู้เขียนหนังสือตามลำดับ และมีหนึ่งเมธอด info สำหรับแสดงรายละเอียดของหนังสือ จากนั้นเราประกาศ Static property สำหรับนับจำนวนหนังสือที่ถูกสร้างขึ้น

static count = 0;

Static property สามารถสร้างได้โดยการใส่คำสั่ง static ที่หน้าชื่อของตัวแปร count และสามารถมีค่าเริ่มต้นได้ เราได้กำหนดค่าเริ่มต้นให้กับมันเป็น 0 และมันจะถุูกใช้งานสำหรับนับจำนวนออบเจ็คของหนังสือที่ถูกสร้างขึ้น

constructor(title, author) {
    this.title = title;
    this.author = author;

    Book.count++;
}

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

console.log(`Total books created: ${Book.count}`);

ในตอนท้ายเป็นการแสดงค่าจากตัวแปร Book.count ออกทางหน้าจอ ซึ่งนี่สามารถบอกเราได้ว่ามีออบเจ็คของหนังสือถูกสร้างไปแล้วเป็นจำนวนเท่าไร หรือกล่าวอีกนัยหนึ่ง มันคือจำนวนครั้งที่คอนสตรัคเตอร์ของคลาส Book ที่ถูกเรียกใช้งานนั่นเอง

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

user.js
class User {
    static LEVEL_ADMIN = 1;
    static LEVEL_REGISTERED = 2;
    static LEVEL_GUEST = 3;

    constructor(id, name) {
        this.id = id;
        this.name = name;
    }

    setLevel(level) {
        this.level = level;
    }
}

let user1 = new User(1, "Matteo");
user1.setLevel(User.LEVEL_ADMIN);

let user2 = new User(2, "Kris");
user2.setLevel(User.LEVEL_GUEST);

console.log(user1);
console.log(user2);

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

User { id: 1, name: 'Matteo', level: 1 }
User { id: 2, name: 'Kris', level: 3 }

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

user1.setLevel(User.LEVEL_ADMIN);
...
user2.setLevel(User.LEVEL_GUEST);

จากนั้นในตอนกำหนดระดับผู้ใช้งานให้กับออบเจ็คเราจะใช้ค่าผ่าน Static property ของคลาสแทนการกำหนดค่าเป็นตัวเลขตรงๆ นี่เป็นแนวคิดการใช้งาน Static property ในรูปแบบของ Enum ที่ช่วยให้โค้ดมีความหมายและอ่านเข้าใจได้ง่ายขึ้น

คุณอาจจะคิดว่าเราสามารถประกาศระดับการใช้งานเป็นค่าคงที่ด้วยคำสั่ง const ก็ได้ แต่ในการทำเช่นนี้ คุณจะต้องประกาศมันไว้ที่นอกคลาส และเนื่องจากค่าเหล่านี้ใช้เกี่ยวกับคลาส User ดังนั้นมันจึงเหมาะสมที่จะประกาศมันเป็น Static property ของคลาส

Static setter and getter

เช่นเดียวกับ Static method และ Static property ในภาษา JavaScript นั้นคุณสามารถประกาศ Setter และ Getter เมธอดให้เป็นแบบ Static ได้ โดยการระบุคำสั่ง static ไว้ที่หน้าชื่อของเมธอดเหล่านี้ นี่เป็นตัวอย่างของโปรแกรมคำนวณหาพื้นที่ของวงกลมที่สนับสนุนการเปลี่ยนหน่วยได้

circle.js
class Circle {
    static #unit = "cm";

    static set unit(value) {
        if (typeof value !== "string") {
            throw new TypeError("Unit must be string")
        }
        Circle.#unit = value;
    }

    static get unit() {
        return Circle.#unit.toUpperCase();
    }

    constructor(radius) {
        this.radius = radius;
    }

    getArea() {
        return this.radius * this.radius * Math.PI;
    }
}

let c1 = new Circle(5);
let c2 = new Circle(2);

console.log(`Area of c1 is ${c1.getArea()} ${Circle.unit}.`);
console.log(`Area of c2 is ${c2.getArea()} ${Circle.unit}.`);

Circle.unit = "in";

console.log(`Area of c1 is ${c1.getArea()} ${Circle.unit}.`);
console.log(`Area of c2 is ${c2.getArea()} ${Circle.unit}.`);

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

Area of c1 is 314.1592653589793 CM.
Area of c2 is 78.53981633974483 CM.
Area of c1 is 314.1592653589793 IN.
Area of c2 is 78.53981633974483 IN.

ในตัวอย่างนี้ เราได้สร้างคลาส Circle ที่เป็นคลาสของวงกลมที่มี Property radius สำหรับเก็บรัศมีของวงกลม และเมธอด getArea สำหรับคำนวณหาพื้นที่ของวงกลมจากรัศมีของมัน และเรามี Static property #unit สำหรับเก็บหน่วยของความยาวที่จะใช้ในโปรแกรมกับออบเจ็คของวงกลมทั้งหมด

static set unit(value) {
    if (typeof value !== "string") {
        throw new TypeError("Unit must be string")
    }
    Circle.#unit = value;
}

static get unit() {
    return Circle.#unit.toUpperCase();
}

จากนั้นเราได้ประกาศ Getter และ Setter เมธอดแบบ Static สำหรับอ่านและกำหนดค่าของ Property #unit แทนการเข้าถึงมันตรงๆ เนื่องจากมันมีระดับการเข้าถึงเป็นแบบ Private ที่มีการป้องกันการเข้าถึงค่าจากภายนอกของคลาส

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

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

บทความนี้เป็นประโยชน์หรือไม่?Yes·No