Jakiś czas temu zagłębiając się w jedną z lepszych książek o JS – „JavaScript – Zasady Programowania Obiektowego” Nicholas C. Zakas natrafiłem na jedną z funkcjonalności języka, której do tej pory nie wykorzystywałem. Mam na myśli atrybuty właściwości funkcji dostępowych. Dzięki tym atrybutom i metodzie Object.defineProperty() w dowolnej chwili do każdego obiektu można dodać funkcję dostępowe. Generalnie chodzi o tzw. setter oraz getter.
Idąc dalej tym tropem, natrafiłem na ciekawy przykład wykorzystania metody get() oraz set() w specyfikacji MDN (https://developer.mozilla.org) a mianowicie o opisany przez nich „self-archiving object.”. Poniżej dokładna kopia z MDN:

 

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('get!');
      return temperature;
    },
    set: function(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

 

 

Postanowiłem trochę „rozbudować” powyższy przykład i zastosować go jako wrzozec archiwizacji danych w obiekcie.
Poniższy przykład można wykorzystać jako zapamiętanie historii punktów gracza. Zdobyte punkty gracza wpisywane są do właściwości points obiektu player. Natomiast metoda player.getHistoryPoints() zwraca obiekt zawierający historię zdobywanych punktów – data i ilość zdobytych punktów.

 

 

var player = (function() {
  var points = 0, pointsHistory = [], _player = {};
  
  // metody publiczne
  _player.getHistoryPoints = getHistoryPoints
  
  // implementacja metod
  function getHistoryPoints() {
     // wykorzystanie metody slice() tablicy, pozwala zapobiec nadpisaniu
    // tablicy pointsHistory. Bezpośrednie zwrócenie tablicy pointsHistory
    // (a dokładniej referencji do tej tablicy, ponieważ w JS tablice są obiektami)
    // pozwoliłoby ją nadpisać np.
    // var history = player.getHistoryPoints(); history.length = 0;
    return pointsHistory.slice(0);
  }
  
  // funkcja pomocnicza zwracająca czas w formacie HH:MM:SS
  function getTime() {
    var date = new Date(),
        h = date.getHours().toString().length === 2 
    				? date.getHours() : '0' + date.getHours(),
        m = date.getMinutes().toString().length === 2 
    				? date.getMinutes() : '0' + date.getMinutes(),
        s = date.getSeconds().toString().length === 2 
    				? date.getSeconds() : '0' + date.getSeconds();
    
    return h + ":" + m + ":" + s;
  }  
  
  // implementacji funkcji dostępowych
  Object.defineProperty(_player, 'points', {
    // zwraca aktualną wartość punktów gracz
    get : function() {
      if(typeof points === 'undefined') {
        points = 0;
      }
      
      return points
    },
    
    // ustawienie nowej wartości punktów gracza
    set : function(newPoints) {
      points = newPoints;
      // archiwizacja danych
      pointsHistory.push({
        date   : getTime(),
        points : points
      })
    }
  })
  
  return _player;
  
}());

// testy
console.log(player.points); // 0
console.log(player.getHistoryPoints()); // pusty obiekt []
player.points = 10;
player.points = 12;
player.points = 23;
player.points = 4;
console.log(player.points); // 4 - ostatnie punkty
console.log(player.getHistoryPoints()); // obiekt [{ date : "HH:MM:SS", points : 10 }, ...]