שדות ושיטות של כיתות

שדות

שדות המחלקה מוצהרים ישירות בגוף המחלקה, ולא מוסיפים אותם במפורש כמאפיין של הערך this. עם זאת, התוצאה תהיה זהה: מאפיין שמוגדר על מכונות של המחלקה הזו.

class MyClass {
    myField;
}

const myClassInstance = new MyClass();

myClassInstance;
> MyClass { myField: undefined }

אפשר להתחיל שדה עם ערך. בדרך כלל זהו ערך ברירת מחדל שהלוגיקה במחלקה יכולה להחליף:

class MyClass {
    myResult = false;
    set setValue( myValue ) {
        this.myResult = myValue;
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> Object { myResult: false }

myClassInstance.setValue = true;

myClassInstance;\
> Object { myResult: true }

שדות המחלקה זהים מבחינה פונקציונליות למאפיינים שמצורפים למחלקה באמצעות this. המשמעות היא שאפשר לגשת אליהם ולשנות אותם מחוץ למחלקה כמו כל נכס אחר.

class MyClass {
    myField = true;
}

const myClassInstance = new MyClass();

myClassInstance.myField;
> true

myClassInstance.myField = false;

myClassInstance.myField;
> false;

השדות מהווים את הבסיס לחלק מהתכונות המתקדמות יותר של המחלקות.

שיטות ושדות פרטיים

אי אפשר לגשת לשדות ולשיטות פרטיים מחוץ לכיתה. נכס פרטי משויך למופע של מחלקה. כלומר, כל מכונה מכילה קבוצה של שדות פרטיים ושיטות משלה, כפי שהם מוגדרים במחלקה.

כדי להפוך נכס לפרטי, צריך להוסיף # לתחילת המזהה כשמצהירים עליו:

class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {}
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass { #myPrivateField: true }
    #myPrivateField: true
    <prototype>: Object { … }
        constructor: class MyClass {}
        <prototype>: Object { … }

יש להצהיר על שדה פרטי בגוף המחלקה שמכילה. אפשר לשנות את הערך שלו מאוחר יותר כמאפיין של this, אבל אי אפשר ליצור את השדה באמצעות this.

לא ניתן לגשת לשדות פרטיים ממקומות אחרים בסקריפט. כך לא ניתן לשנות את מאפייני הנתונים מחוץ לשיטות של get ו-setter שסופקו כדי לקיים אינטראקציה עם הערכים שהם מכילים, ותימנע גישה ישירה לשיטות שמיועדות לשימוש רק בתוך הכיתה עצמה.

class MyClass {
    #myResult = false;
    set setValue( myValue ) {
        this.#myResult = myValue;
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass { #myResult: false }

myClassInstance.#myResult = true;
> Uncaught SyntaxError: reference to undeclared private field or method #myResult

myClassInstance.setValue = true;

myClassInstance;\
> MyClass { #myResult: true }

עם זאת, חשוב לזכור שמסופי הפיתוח של דפדפנים בדרך כלל מתירנים מאוד, אם כי לא עקביים לגבי מתן גישה לשדות פרטיים למטרות ניפוי באגים:

class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {
        console.log( "This is inside a private method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass {#myPrivateField: true}

myClassInstance.#myPrivateField;
> true

myClassInstance.#myPrivateMethod();
> "This is inside a private method."
class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {
        console.log( "This is inside a private method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass {#myPrivateField: true}

myClassInstance.#myPrivateField;
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateField

myClassInstance.#myPrivateMethod();
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateMethod

שדות פרטיים מוקפים מאוד לגוף הכיתה שמכילה אותם, כלומר גם למחלקות צאצא אין גישה לשדות פרטיים שמשויכים לכיתת הורה:

class MyClass {
    #myPrivateField = true;
}
class ChildClass extends MyClass {
    childMethod() {
        console.log( this.#myPrivateField );
    }
}
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateField

שדות ושיטות סטטיים

שדות ושיטות סטטיים הם חברים במחלקה עצמה, ולא חברים במכונות של המחלקה הזו. לכן שדות סטטיים מספקים נקודה מרכזית לנתונים שלא יהיו ייחודיים לכל מכונה של מחלקה, אבל יכול להיות שהם יצטרכו להפנות למכונות האלה – לדוגמה, פרטי תצורה משותפים. שיטות סטטיות הן בדרך כלל פונקציות שימושיות לעבודה עם מופעים של מחלקה, כמו השוואה או מיון של מכונות מול שדה שהן מכילות.

כדי להגדיר שיטות ושדות סטטיים בגוף המחלקה, משתמשים במילת המפתח static:

class MyClass {
    static myStaticField;
    static myStaticMethod() {}
}
const myClassInstance = new MyClass();

אפשר גם להשתמש בסימון הנקודות כדי ליצור שיטה סטטית:

class MyClass {
    constructor() {}
}
MyClass.myStaticMethod = function() {}

אי אפשר לגשת למאפיינים סטטיים ממופע של המחלקה, אבל הם זמינים בבונה המחלקה:

class MyClass {
    static myStaticField = true;
    static myStaticMethod() {
        console.log( "A static method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance.myStaticField;
> undefined

myClassInstance.myStaticMethod();
> Uncaught TypeError: myClassInstance.myStaticMethod is not a function

MyClass.myStaticField;
> true

MyClass.myStaticMethod();
> "A static method."

לא חייבים להשתמש בהם מבחינה טכנית, אבל מומלץ להשתמש בשיטות סטטיות כדי ליצור כלי תחזוקה שיעבדו עם מכונות של מחלקה. דוגמאות לכך יכולות לכלול שיטה סטטית ייעודית למיון מכונות של מחלקה, או שיטה סטטית למפעלים שכוללת את ההגדרות הנחוצות ליצירת מכונה של מחלקה והחזרת המופע של המחלקה:

class User {
    constructor( name, email ) {
        this.name = name;
        this.email = email;
    }
    static fromObject( myObject ) {
        return new User( myObject.name, myObject.email ?? "Omitted" );
    }
}
const userObject = {
    "name" : "My Name",
    "email" : "my@email.address"
};
const secondUserObject = {
    "name" : "My Name"
};

const firstUser = User.fromObject( userObject );
const secondUser = User.fromObject( secondUserObject );

firstUser;
> Object { name: "My Name", email: "my@email.address" }

secondUser;
> Object { name: "My Name", email: "Omitted" }

בחינת ההבנה

לאילו מסוגי השדות הבאים אפשר לגשת רק מתוך המחלקה?

שדות פרטיים
שדות מחלקה
Static fields