מחלקות

ES6 הציג ב-JavaScript את המושג 'מחלקות', ששונה ממחלקות בשפות תכנות אחרות. כאן, מחלקות הן פונקציות מיוחדות שמשמשות כתבניות ליצירת אובייקטים שכבר מכילים נתונים, מאפיינים שמשויכים לנתונים האלה ושיטות שקשורות למניפולציה של הנתונים האלה. האובייקטים, המאפיינים והשיטות האלה נקראים יחד 'חברים' במחלקה.

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

class MyClass {}

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

class MyClass {}

typeof MyClass;
> "function"

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

כדי ליצור מופע של מחלקה, משתמשים באופרטור new.

class MyClass {}

const myClassInstance = new MyClass();

myClassInstance;
> Object { }

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

class MyClass {
    classMethod() {
        console.log( "My class method." );
    }
}

const myClassInstance = new MyClass();

myClassInstance.classMethod();
> "My class method."

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

class MyClass {
  classMethod() {
    console.log( "My class method." );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { }
    <prototype>: Object { … }
        classMethod: function classMethod()
        constructor: class MyClass { constructor(myPassedValue) }
        <prototype>: Object { … }

myClassInstance.classMethod();
> "My class method."

יצירת מכונה של מחלקה מפעילה שיטת constructor() מיוחדת שמבצעת 'הגדרה' נדרשת למכונה החדשה שנוצרה ומפעילה את כל המאפיינים שמשויכים אליה. כל הארגומנטים שמועברים למחלקה בזמן יצירת המכונה זמינים לשיטה constructor():

class MyClass {
  constructor( myPassedValue ) {
    console.log( myPassedValue );
  }
}

const myClassInstance = new MyClass( "A string." );
> "A string."

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

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProperty = myPassedValue;
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { instanceProperty: "A string." }

המאפיינים הבאים זמינים גם לכל השיטות בגוף המחלקה:

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProp = myPassedValue;
  }
  myMethod() {
    console.log( this.instanceProp );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance.myMethod();
> "A string."

אם לא תגדירו constructor() למחלקה, מנוע ה-JavaScript יש להניח ש'ברירת המחדל' constructor ריקה. לכל מחלקה יכולה להיות רק שיטה מיוחדת אחת בשם constructor():

class MyClass {
  constructor() {}
  constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor

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

let ClassExpression = class {
    constructor() {}
};

ClassExpression;
> class  {}

אחד הדברים שאפשר להשתמש בביטויי מחלקה אנונימיים הוא פונקציות שבונות מחלקות "תוך כדי תנועה":

function classMaker() {
  return class {
    constructor() {}
  };
}

let MyVariable = classMaker();

MyVariable;
> class  {}

הצהרה מחדש על מחלקה באמצעות הצהרת מחלקה גורמת לשגיאת תחביר:


class MyClass {
    constructor( ) {
        console.log( "My class." );
    }
};

class MyClass {
    constructor() {
        console.log( "My new class." );
    }
};
> Uncaught SyntaxError: redeclaration of class MyClass

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

let ClassExpression = class MyClass { };

ClassExpression = class MyOtherClass {
    constructor( myString ) {
        this.myProp = myString;
    }
};

new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}

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

let MyVariable = class MyClass {};

MyClass;
> Uncaught ReferenceError: MyClass is not defined

MyVariable;
> class MyClass {}

MyVariable.name;
> "MyClass"

כשמאתחלים משתנה באמצעות ביטוי מחלקה, כללי ההגבהה של המשתנה מתעדכנים כמצופה. הצהרות כיתתיות פועלות לפי אותם כללים של "אזור זמן בלתי פעיל" כמו let ו-const, ומתנהגות כאילו הן לא הועלו לראש ההיקף הנוכחי שלהן. כלומר, הפעלת מחלקה לפני הצהרת הכיתה גורמת לשגיאה:

{
    let myVar = new MyClass( "Property string." );

    class MyClass {
        myProp;

        constructor( myString ) {
            this.myProp = myString;
        }
    };
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization

בחינת ההבנה

איזה מהמשפטים הבאים מגדיר נכון מחלקה?

class MyClass {}
myClass = class {}
new class()

כמה שיטות של constructor() יכולות להיות לכיתה?

אחד
אין
ללא הגבלה