אינטרנט ישראל
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
ראשי » מדריכים » טייפסקריפט » טייפסקריפט: קלאסים

טייפסקריפט: קלאסים

רן בר-זיק אפריל 24, 2022 7:07 am 3 תגובות

הסבר על איך משתמשים בקלאסים בטייפסקריפט ואיך טייפסקריפט הופכת את ג'אווהסקריפט להרבה יותר OOP/

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

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

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

class User {
    userId: number;
    userName: string;

    constructor(userId: number, userName: string) {
            this.userName = userName;
            this.userId = userId;
    }

    getUserStatus() : string {
        // Some Call or Business logic
        return 'admin';
    }
}

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

let userA = new User(1, 'Ran');
let userB = new User('1', 'Ran'); // Argument of type 'string' is not assignable to parameter of type 'number'.
let userAStatus = userA.getUserStatus();
if (userAStatus * 5 > 10) { // The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.(2362)
} 

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

interface User {
    userId: number;
    userName: string;
    getUserStatus():string;
}


class BasicUser implements User {
    userId: number;
    userName: string;
    constructor(userId: number, userName: string) {
            this.userName = userName;
            this.userId = userId;
    }

    getUserStatus() : string {
        // Some Call or Business loginc
        return 'admin';
    }
}

שימו לב שהאינטרפייס פה רק בודק התאמה – כמו כל טייפסקריפט. הוא לא יוצר דברים בקלאס (אומר את זה כי יש לאינטרפייס קשר לקלאס ב-OOP).

או קיי, אז אין הפתעות גדולות, כן חשוב להתעדכן על ענייני private, protected ו-public.

סימון Private, Public או Protected

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

class BasicUser {
    userId: number;
    userName: string;
    constructor(userId: number, userName: string) {
            this.userName = userName;
            this.userId = userId;
    }

    private getUserStatus() : string {
        // Some Call or Business loginc
        return 'admin';
    }
}

let userA = new BasicUser(1, 'Ran');
let userAStatus = userA.getUserStatus(); // Property 'getUserStatus' is private and only accessible within class 'BasicUser'.

מאז שטייפסקריפט הכניס את זה אז גם בג'אווהסקריפט זה נכנס בתקן ES2021 – אז באמת לשיקולכם אם להשתמש בזה בטייפסקריפט או בג'אוהסקריפט טהור. אני אומר שאם כבר משתמשים בטייפסקריפט אז להשתמש בזה ולא ב-ES2021.

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

class BasicUser<T, U> {
    userId: T;
    userName: U;
    constructor(userId: T, userName: U) {
            this.userName = userName;
            this.userId = userId;
    }

    private getUserStatus() : string {
        // Some Call or Business loginc
        return 'admin';
    }
}

let userA = new BasicUser<number, string>(1, 'Ran');
let userB = new BasicUser<string, string>('abcdef-24564', 'Ran');

קלאס אבסטרקטי

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

abstract class User {
    userId: number;
    userName: string;
    constructor(userId: number, userName: string) {
            this.userName = userName;
            this.userId = userId;
    }

    getUserStatus() : string {
        // Some Call or Business loginc
        return 'admin';
    }
}

class BasicUser extends User {

    getUserPoints() :number {
        // some logic
        return 100;
    }

}

let userA = new User(1, 'Ran'); // Cannot create an instance of an abstract class.
let userB = new BasicUser(1, 'Ran');
console.log(userB.getUserStatus()); // admin
console.log(userB.getUserPoints()); // 100

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

Readonly

לבסוף, תכונה משובבת נפש שקיימת בג'אווהסקריפט באופן מסוים היא readonly בקלאס. בגדול, כאשר אני מוסיף לתכונה בקלאס את המילה readonly, אי אפשר לשנות אותה. בעוד שזו התנהגות טבעית בשפות אחרות, בג'אווהסקריפט אני יכול לשנות תכונות באובייקט שנוצר מהקלאס גם בלי set\get. אם אני מוסיף readonly, טייפסקריפט לא תיתן לעשות את התעלול הזה:

class User {
    readonly userId: number;
    userName: string;

    constructor(userId: number, userName: string) {
            this.userName = userName;
            this.userId = userId;
    }

    getUserStatus() : string {
        // Some Call or Business logic
        return 'admin';
    }
}


let userA = new User(1, 'Ran'); 
userA.userId = 5; // Cannot assign to 'userId' because it is a read-only property.

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

במאמר הבא אנו נדון על Declaration Files. שזו הדרך לתאר את הקוד שלנו לטייפסקריפט ולהשתמש בספריות. אותם d.ts שבטח יצא לכם לראות פה ושם.

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

3 תגובות

  1. משתמש אנונימי (לא מזוהה) הגב אפריל 26, 2022 בשעה 7:59 pm

    אבל מה בעצם קורה שם בפנים במחלקה האבסטרקטית? זו בעצם מחלקה רגילה של es6 רק שטייפסקריפט צועק עליך אם אתה מנסה לעשות לה new ?

    בכלל בג'אווהסקריפט, כשמחלקה עושה extend למחלקה אחרת ואז אני יוצר instance של המחלקה השניה אז איפה המחלקה הראשונה נמצאת? היא מקבלת instance משל עצמה בתור הפרוטוטייפ של הפרוטוטייפ? או שהכל מתערבב לפרוטוטייפ אחד?

    • אבי הגב אוגוסט 17, 2022 בשעה 10:42 pm

      לכאורה Class A נמצא ב Prototype של ה Instance של Class B (איזה היבריש).

  2. אבי הגב אוגוסט 17, 2022 בשעה 10:39 pm

    אז מה בעצם ההבדל בין מחלקה (קלאס) אבסטרקטי, לבין אינטרפייס?
    אינטרפייס הוא אובייקט עם טייפים בלבד, ללא מתודות עם קוד, בעוד שקלאס אבסטרקטי יכול לכלול מתודות של ממש?
    אם כן, כדאי שיודגש בגוף המאמר.
    תודה…

השארת תגובה

ביטול

ללמוד ג'אווהסקריפט בעברית

ללמוד לתכנת ג'אווהסקריפט בעברית שגייס יותר משלוש מאות אלף שקל ולמעלה מ-2000 תומכים - בואו ללמוד עכשיו איך לתכנת.

רשימת הנושאים
  • מדריכים
    • ריאקט
    • טייפסקריפט
    • ECMAScript 6
    • ES20XX
    • Node.js
    • Express
    • רספברי פיי
    • Babel
    • docker
    • MongoDB
    • Git
    • לימוד MySQL
    • SASS
    • jQuery
    • CSS3
    • HTML 5
    • SVN
    • LESS
  • פיתוח אינטרנט
    • פתרונות ומאמרים על פיתוח אינטרנט
    • jQuery Scripts
    • jQuery למתקדמים
    • יסודות בתכנות
    • נגישות אינטרנט
  • חדשות אינטרנט
  • מידע כללי על אינטרנט
    • רשת האינטרנט
    • בניית אתרי אינטרנט
  • rss logo

    לכל המאמרים

    לכל המאמרים שפורסמו באינטרנט ישראל משנת 2008 ועד עכשיו.
  • rss logo

    RSS Feed

    משתמשים בקורא RSS? אם כן, עקבו אחרי אינטרנט ישראל באמצעות פיד ה-RSS!
    מה זה RSS?
  • Twitter logo

    עקבו אחרי בטוויטר

    בחשבון הטוויטר שלי אני מפרסם עדכונים מהירים על חדשות בתחום התכנות והיזמות, התרעות על מצבי חירום ורכילות בוערת על תחום הווב.
    מה זה טוויטר?
  • facebook like image

    ערוץ הטלגרם של אינטרנט ישראל

    בערוץ הטלגרם של אינטרנט ישראל אני מפרסם את הפוסטים של באתר וכן עדכונים טכנולוגיים נוספים.
    מה זה טלגרם?
  • github logo

    הפרויקטים שלי בגיטהאב

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

כל הזכויות שמורות לרן בר-זיק ולאינטרנט ישראל | מדיניות הפרטיות של אתר אינטרנט ישראל | אתר אינטרנט ישראל נגיש לפי תקן WCAG 2.0 AA | הצהרת הנגישות של האתר | אבטחת מידע ודיווח על בעיית אבטחת מידע

גלילה לראש העמוד