ES6 Singleton

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

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

1. הגדרת מחלקה ב ES6

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

class Store extends EventEmitter {
  
  trigger() {
    this.emit(CHANGE_EVENT);
  }
  
  subscribe(callback) {
    this.on(CHANGE_EVENT, callback);
  }
  
  unsubscribe(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }
};

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

class KittenStore extends Store {
  constructor() {
    super();
    this.kittens = [];
  }
  
  pet() {
    this.kittens.forEach(function(kitten) {
      kitten.prr();
    });
    this.trigger();
  }  
}

 

2. אבל איך יוצרים Singleton?

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

let usersStore = new class extends Store {
  constructor() {
    super();
    this.items = [];
  }
  
  add(item) {
    this.items.push(item);
    this.trigger();
  }
}();

usersStore.subscribe(function() {
  document.body.innerHTML += '<b>Add</b>';
});

usersStore.add('demo');

// this doesn't work:
// var anotherOne = new usersStore();

מוזמנים גם לנסות את הדוגמא בקודפן הבא:
http://codepen.io/ynonp/pen/JGoQEK