ES2021 private methods

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

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

ראשית חשוב להבהיר שג'אווהסקריפט היא לא שפה מונחית עצמים, מה שגויי הים קוראים לו Object oriented. היא Prototype based. מה זה אומר בפועל? הבסיס של ג'אווהסקריפט הוא פרוטוטייפ. כן, הדבר הזה שכל מתכנת ג'אווהסקריפט מנוסה מכיר אם הוא מעלעל בכלי מפתחים. הפרוטוטייפ בגדול אומר שאני יכול ליצור אובייקטים שהם הפרוטוטייפ ועל בסיסים ליצור אובייקטים אחרים. בניגוד לאובייקטים בשפה מונחית עצמים, האובייקטים של ג'אווהסקריפט הם אובייקטים אמיתיים שיש להם זכות קיום. אובייקטים שיורשים מהם מקבלים את התכונות שלהם ישירות.

אני חושב שזו הדוגמה הכי טובה לפרוטוטייפ. הנה  אובייקט1 שהוא הפרוטוטייפ, אובייקט2 שנוצר ממנו. אני משנה בזמן ריצה את הראשון? שיניתי את השני.

const myobj1 = {
  prop1: 'Value of prop1',
  prop2: 'Value of prop2',
  method: () => console.log('method activated'),
}
const myobj2 = Object.create(myobj1);

console.log(myobj2.prop1); // Value of prop1
myobj1.prop1 = 'Muhahahahah';
console.log(myobj2.prop1); // Muhahahahah

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

function MyClass(prop1, prop2) {                 
    this.prop1 = prop1;                        
    this.prop2 = prop2;
}

let myClass  = new MyClass(3, 4); // object instantiation ('new' keyword)
console.log(myClass instanceof MyClass); // true
console.log(myClass.prop1); // 3
console.log(myClass.prop2); // 4

MyClass.prototype.multiple = function () {     
    return (this.prop1 * this.prop2);
}

console.log(myClass.multiple()); // 12

ככה ג'אווהסקריפט עובדת מאחורי הקלעים. אין לה קלאסים. יאפ, גם לא ב- ES6.

רגע, מה??? למה לג'אווהסקריפט אין קלאסים???

אבל כן יש לנו קלאסים! אפילו אתה לימדת על קלאסים באתר אז מה זאת אומרת אין לנו קלאסים? בג'אווהסקריפט שהם הקלאסים שאנו מכירים כיום הם בעצם "קיצור" של פרוטוטייפ. קיצור שנקרא סוכר סינטקסטי. syntactic sugar. כשאני יוצר קלאס, אני יוצר בדיוק את מה שיש למעלה. שימו לב. ככה נראה הקלאס שמימשתי עם הפונקציה שלמעלה:

class MyClass { 
    constructor (prop1, prop2) {                 
        this.prop1 = prop1;                        
        this.prop2 = prop2;
    }
    multiple () {
        return (this.prop1 * this.prop2);
    }
}

let myClass  = new MyClass(3, 4); // object instantiation ('new' keyword)
console.log(myClass instanceof MyClass); // true
console.log(myClass.prop1); // 3
console.log(myClass.prop2); // 4
console.log(myClass.multiple()); // 12

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

class MyClass { 
    constructor (prop1, prop2) {                 
        this.prop1 = prop1;                        
        this.prop2 = prop2;
    }
    multiple () {
        return (this.prop1 * this.prop2);
    }
}

let myClass  = new MyClass(3, 4); // object instantiation ('new' keyword)
console.log(myClass instanceof MyClass); // true
console.log(myClass.prop1); // 3
console.log(myClass.prop2); // 4
console.log(myClass.multiple()); // 12
MyClass.prototype.sum = function () {     
    return (this.prop1 + this.prop2);
}
console.log(myClass.sum()); // 7

למה זה עובד? שוב, כי נכון, יש את המילה השמורה class, את המתודה constructor. הכל כמו Java או כמו שפה מתורבתת אחרת אבל בפועל? זה פרוטוטייפ. לא מאמינים? הנה הקוד שלעיל להרצה. הפעילו את כלי המפתחים ותציצו על ה __proto__ נסו לשנות את זה. רוצים צחוקים? תראו את זה למתכנת ג'אווה ותראו אותו מוציא את הגרזן. ועוד לפני שדיברתי שמדובר על דלגציה של מתודות ולא ירושה.

See the Pen Adding method to ES6 Class by Ran Bar-Zik (@barzik-the-vuer) on CodePen.

אז זו הסיבה שאני קצת לא אוהב קלאסים. נכון, הם מארגנים את הקוד וזה באמת נחמד, אבל יוצרים בעיות ביצועים, יש בעיות bind איתם והכי גרוע – הם מרגילים מתכנתים שאמורים לחשוב פרוטוטייפית לחשיבה של קלאסים. ואז כל מיני תפלצות כמו base class וזוועות אחרות. רוצים לתכנת בקלאסים? לכו תתכנתו בג'אווה ותעזבו את ג'אווהסקריפט במנוחה!

ואחרי שסיימתי עם המלטדאון, בואו נתקדם, או קיי? אז יש מתכנתים רבים וטובים שחושבים כמוני אבל אני במיעוט פה, ה-TC39 מקדמים את הקלאסים והפיצ'ר החדש הוא מתודות פרטיות! דבר שלא היה קיים בקלאסים עד כה. אז כלפי אלו שדילגו על כל הערימה הזו, אני מעמיד פנים שמדובר בדבר מהמם ומרגש. אבל אתם, קוראי היקרים שלא דילגו ישר לת'כלס, יודעים שבסתר ליבי אני מתעב את הקלאסים ואת הפיצ'ר הזה. מתעב! 😡😔

אז איך משתמשים בזה

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

class MyClass { 
    constructor (prop1, prop2) {                 
        this.prop1 = prop1;                        
        this.prop2 = prop2;
    }
    multiple () {
        return this.#privateMethod(this.prop1, this.prop2)
    }
    #privateMethod(arg1, arg2) {
      return (this.prop1 * this.prop2);
    }
}

let myClass  = new MyClass(3, 4); // object instantiation ('new' keyword)

console.log(myClass.multiple()); // 12
console.log(myClass.#privateMethod(5, 3)); // Uncaught SyntaxError: Private field '#privateMethod' must be declared in an enclosing class 

מתודות פרטיות מתחילות עם #. כן, זה הכל וזה עובד יפה מאוד.

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

See the Pen Adding private method to ES6 Class by Ran Bar-Zik (@barzik-the-vuer) on CodePen.

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

פוסטים נוספים שכדאי לקרוא

צילום מסך של סוואגר
יסודות בתכנות

openAPI

שימוש בתשתית הפופולרית למיפוי ותיעוד של API וגם הסבר בסיסי על מה זה API

תמונה מצוירת של רובוט שמנקה HTML
יסודות בתכנות

סניטציה – למה זה חשוב

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

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