почему мы используем `Boy.prototype = new Human;` для имитации наследования? - PullRequest
4 голосов
/ 13 мая 2011

Я не понимаю, почему все используют Boy.prototype = new Human; для имитации наследования. Смотри, что мы хотим, это функция права? мы можем сделать это без создания нового A (фактически создание нового A дает нам нежелательные результаты в том смысле, что мы на самом деле выполняем функцию создания экземпляров, а это не то, что нам нужно)

Так разве это не лучшее решение?

for (var prop_name in Human.prototype) {
Object.defineProperty(
          Boy.prototype,
          prop_name,
          Object.getOwnPropertyDescriptor(Human.prototype,prop_name)
        );
}

Скажем, мы такие особенные и хотим не только перечислимые свойства в Human.prototype, но мы все же могли бы достичь его, используя Object.getOwnPropertyNames и вызывая его в цепочке прототипов, которая, в свою очередь, доступна нам через Object.getPrototypeOf.

Так в чем же состоит преимущество Boy.prototype = new Human; для симуляции наследования, когда у нас есть более подходящие варианты?

Ответы [ 2 ]

4 голосов
/ 13 мая 2011

Лучшим вариантом является создание промежуточного звена для хранения прототипа.

function extend(clazz, superclass) {
    var intermediate = function() {};
    intermediate.prototype = superclass.prototype;
    clazz.prototype = new intermediate();
    // Following line is optional, but useful
    clazz.prototype.constructor = clazz;
}

Это позволяет избежать ненужного копирования, но все равно означает, что вам не нужно создавать экземпляр объекта, который будет работать в его конструкторе. Он также устанавливает цепочку прототипов, чтобы вы могли использовать instanceof. Это также не приводит к загрязнению прототипа суперкласса, что могут некоторые антипаттерны наследования.

Для полноты вашему подклассу следует вызвать конструктор суперкласса в своем конструкторе, что вы можете сделать с помощью Superclass.call(this);.

РЕДАКТИРОВАТЬ : Начиная с ES5, вы можете заменить вызовы на extend на

Subclass.prototype = Object.create(Superclass.prototype);

, который делает то же самое.

4 голосов
/ 13 мая 2011
  • Он правильно устанавливает цепочку прототипов, что означает, что instanceof и isPrototypeOf() будут работать
  • Это менее многословно

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

function Boy(name) {
    if (arguments.length == 1) {
        this.name = name;
        // Do other initialization
    }
}

... или перенести инициализацию в отдельный метод, который должен вызываться явно:

function Boy(name) {}

Boy.prototype.init = function(name) {
    this.name = name;
    // Do other initialization
}

Это имеет очевидныйНедостаток необходимости не забывать вызывать init() всякий раз, когда вы создаете новый Boy.

В средах ECMAScript 5 (например, в текущих версиях большинства браузеров), лучшим вариантом может быть ECMAScript 5 Object.create(), который позволяет вам создать объект, который наследуется непосредственно от другого объекта и устанавливает цепочку прототипов для вас.Это можно эмулировать (но только приблизительно: см. Object.defineProperty в ES5? ) в средах, отличных от ES5:

if (!Object.create) {
    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...