9.8.5. Подклассы и ECMAScript 5

В примере 9.22 демонстрируется порядок создания подклассов с использованием возможностей ECMAScript 5. В нем определяется класс stringSet, наследующий класс AbstractWritableSet из примера 9.16. Основная особенность этого примера заключается в использовании функции Object.сreate() для создания объекта-прототипа, наследующего прототип суперкласса, и в определении свойств вновь созданного объекта. Как уже отмечалось выше, основная сложность этого подхода заключается в необходимости использовать неудобные дескрипторы свойств.

Другой интересной особенностью этого примера является передача значения null функции Object.сreate() при создании объекта, не наследующего ничего. Этот объект используется для хранения элементов множества, а тот факт, что он не имеет прототипа, позволяет вместо метода hasOwnProperty() использовать оператор in.

Пример 9.22. StringSet: определение подкласса множества с использованием ECMAScript 5

function StringSet() {

  this.set = Object.create(null); // Создать объект без прототипа

  this.n = 0;

  this.add.apply(this, arguments);

}

// Обратите внимание, что Object.create позволяет обеспечить наследование

// прототипа суперкласса и определить методы за счет единственного вызова.

// Поскольку при создании свойств мы не указываем значения атрибутов writable,

// enumerable и configurable, они по умолчанию получают значение false.

// Доступность методов только для чтения усложняет их переопределение в подклассах.

StringSet.prototype = Object.create(AbstractWritableSet.prototype, {

  constructor: { value: StringSet },

  contains: { value: function(x) { return x in this.set; } }.

  size: { value: function(x) { return this.n; } },

  foreach: { value: function(f,c) { Object.keys(this.set).forEach(f.c); } }.

  add: {

    value: function() {

      for(var і = 0; і < arguments.length; i++) {

        if (!(arguments[i] in this.set)) {

          this.set[arguments[i]] = true;

          this.n++;

        }

      }

      return this;

    }

  ),

  remove: {

    value: function() {

      for(var і = 0; і < arguments.length; i++){

        if (arguments[i] in this.set) {

          delete this.set[arguments[i]];

          this, n--;

        }

      }

      return this;

    }

  }

});