JavaScript — шаблон динамического прототипа наследование паразитной комбинации

#javascript #oop #inheritance #design-patterns

#javascript #ооп #наследование #шаблоны проектирования

Вопрос:

Я работаю с профессиональным JavaScript для веб-разработчиков, и у меня есть вопрос, касающийся создания объектов и наследования. В книге шаблон динамического прототипа обсуждается как хороший способ создания комбинации Конструктор / шаблон прототипа, сохраняя конструктор и прототип инкапсулированными в определение объекта. Вот так:

 function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;

  if (typeof this.sayName != "function") {
    Person.prototype.sayName = function () {
      return this.name;
    };
  }
}
  

Из всех шаблонов создания объектов, обсуждаемых в книге, мне показалось, что этот выглядит лучше всего. Затем, обсуждая наследование, в книге говорится, что наследование паразитных комбинаций считается оптимальной парадигмой наследования. Следующим образом:

 function inheritPrototype(subType, superType) {
  var prototype = Object.create(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

SuperType.prototype.sayName = function() {
  return this.name;
};

function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {
  return this.age;
}
  

Как вы можете видеть, этот код использует комбинацию Конструктор / шаблон прототипа для создания объектов, где прототипы объявляются вне процесса создания исходного объекта. Мой вопрос в том, есть ли какие-либо проблемы с объединением шаблона динамического прототипа с наследованием паразитной комбинации, например:

 function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];

  if (typeof this.sayName != "function") {
    SuperType.prototype.sayName = function() {
        return this.name;
    };
  }
}

function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;

  if (typeof this.sayAge != "function") {
    SubType.prototype.sayAge = function() {
        return this.age;
    };
  }
}

inheritPrototype(SubType, SuperType);
  

Я протестировал это в здесь jsfiddle, и, похоже, все работает нормально, я просто хотел убедиться, что я не упустил чего-то, что позже вызовет проблемы при использовании этого шаблона / наследования.

Кроме того, насколько я знаю, эта книга немного старше, существуют ли новые стандарты для создания объектов и наследования?

Комментарии:

1. inheritPrototype необходимо использовать Object.create не Object

2. Я должен сказать, что «шаблон динамического прототипа» выглядит довольно уродливо на мой взгляд… Также методы прототипа должны быть статическими, а не динамическими, поэтому можно утверждать, что создавать их в конструкторе (даже если только динамически) — плохая практика. Если вы ищете синтаксическую инкапсуляцию, лучше используйте IIFE вокруг конструктора наследование прототип или просто используйте классы ES6.

Ответ №1:

Оба подхода кажутся нарушенными.

Данные свойства прототипа объекта должны быть доступны, даже если функция конструктора еще не была вызвана. С другой стороны, похоже, что это нарушает принцип единой ответственности, потому что конструктор отвечает за определение прототипа, в то время как он должен просто инициализировать создаваемый объект.

Только один вопрос: как бы вы наследуете данного объекта прототипа до базового объекта не построено?:

 var B = Object.create(A.prototype);
  

Подождите! A.prototype не будет содержать ожидаемых свойств, если только какой-то код не вызовет new A() раньше!

 // Ugly as hell!
new A();
var B = Object.create(A.prototype);
  

В заключение, не пытайтесь сокращать JavaScript: лучше изучить его и не пытаться обернуть наследование бесполезными / бессмысленными функциями.

На самом деле, стандарты ECMA-Script 6 и выше уже определили синтаксический сахар, чтобы сделать цепочку прототипов JavaScript похожей на классическое наследование:

 class B extends A 
{
}
  

…что абсолютно эквивалентно:

 function B() {}
B.prototype = Object.create(A.prototype);