Что нужно для вызова () в прототипе наследования

У меня возникли проблемы с расшифровкой прототипного наследования в JavaScript, и я решил опубликовать его здесь. Рассмотрим этот простой пример:

function Employee() {
    this.name = "Rob";
    this.dept = "R&D";
}

function Manager() {
    //Employee.call(this);
    this.reports = ["Report 1", "Report 2", "Report 3"];
}

Manager.prototype = Object.create(Employee.prototype);

Employee.prototype.type = "human";
m = new Manager();
console.log(m.name); //undefined
console.log(m.type); //human

Что я не могу понять, так это полезность линии Employee.call(this), Поскольку мы собираемся установить Employee.protoype в качестве прототипа Manager, то для этого необходимо (как я вижу) явное принудительное создание переменных в Employee с помощью call()? Ранее я думал, что это может быть потому, что нет объекта Employee существует, и наследование JS не может работать без объектов, поэтому call() здесь служил "завершить сборку объекта". Но тогда type свойство отражается в менеджере без необходимости call(), который доказывает, что нам не нужен жесткий объект для выполнения наследования (я имею в виду, что подойдет только определение функции конструктора класса).

Надеюсь, я не сделал это слишком сложным. Короче говоря: почему call() нужен здесь, и почему собственность type работать без call() (если call() это важно, то есть).

3 ответа

Решение

Цель Employee.call(this) это добавить атрибуты имени и отдела к экземплярам Manager.

Использование call() это больше по соглашению, и это позволяет изменить вызывающего абонента (это) на месте.

Недвижимость type работал, так как вы прошли через интерфейс прототипа.

Если вы раскомментируете Employee.call(this)тогда m.name станет 'Rob'.

Несмотря на то, что прототип наследуется, именно здесь определяется тип "человек", без вызова Employee вы не "инициализируете базовый класс" и не запускаете код внутри Employee() конструктор. Тот факт, что Employee является прототипом Manager, не гарантирует, что вы захотите запустить конструктор Employee при создании менеджера.

В отличие от некоторых языков, где вы можете позвонить super()Вы должны вызвать инициализатор для базового класса по имени. Это похоже на C++:

class Manager : public Employee {
public:
    Manager() : Employee() {}
};

Вы также можете решить, когда вызвать родителя и выполнить дополнительную логику, когда автоматический вызов не даст вам такой возможности:

function Employee(name) {
    this.name = name;
    this.dept = "R&D";
}

function Manager(name) {
    // Add the title to the name, first
    var mgrName = name + ' (Manager)';

    Employee.call(this, mgrName);
    this.reports = ["Report 1", "Report 2", "Report 3"];
}

Manager.prototype = Object.create(Employee.prototype);
m = new Manager('Bill');

.type (и другие прототипно наследуемые свойства) работают, да.
Но .name а также .dept нет, они не были созданы на m! Вы были совершенно правы, Employee.call(this) требуется для полной инициализации. Это super вызов конструктора, который вы не должны опускать.

Другие вопросы по тегам