Как объединить функцию конструктора и свойство прототипа

#javascript #constructor #prototype #prototypal-inheritance #object-properties

#javascript #constructor #прототип #прототипирование-наследование #объект-свойства

Вопрос:

Я пытаюсь разобраться в том, как работают прототипы. У меня есть этот пример:

 function Person(name) {
    if (arguments.length > 0)
        this.init(name);
}

Person.prototype.init = function(name) {
    this.name = name();
}
Employee.prototype = new Person();

function Employee (name, id) {
    if (arguments.length > 0) {
        this.init(name);
        this.id = id;
     }
}

var employee = new Employee("frank",01);
alert(employee.name);//returns frank
  

Я бы попытался выяснить, как объединить первые два раздела и назначить свойство «init» в конструкторе функции. У меня есть это, но оно ничего не возвращает:

 function Person(name) {
    if (arguments.length > 0)
        this.init = function(name) {
    this.name = name;
        }
}
Employee.prototype = new Person();

function Employee (name, id) {
    if (arguments.length > 0) {
        this.init(name);
        this.id = id;
     }
}

var employee = new Employee("frank",01);
alert(employee.name);//returns nothing
  

Я предполагаю, что я делаю что-то неправильно при назначении init, но я не знаю, что. Изменение исходного свойства на

 this.init(name) = function(name) {
  

тоже не работает.

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

1. Старайтесь вообще не использовать какой-либо init метод! Просто выполняйте работу в конструкторе!

Ответ №1:

Вы хотите передать имя инициализируемого свойства от Employee к Person?

Это делается следующим образом:

 // Create a constructor-function for your Person-Object.
function Person(name) {
    this.name = name;
}

// Create the constructor-function for an Employee-Object that extends Person
function Employee(name) {
   // Call the constructor-function from Person
   Person.call(this, name);
}

// Let the prototype of Employee be Person.prototype (Employee extends Person)
Employee.prototype = Object.create(Person.prototype);
// By changing the prototype of Employee we have lost our constructor-function Employee()
// so we have to recover it.
Employee.prototype.constructor = Employee;
  

Возможно, вы ожидаете, что суперконструктор будет вызываться неявно, как вы, возможно, знаете это из других языков, таких как Java. Но этого не происходит в JavaScript. Вы должны сделать это самостоятельно, вызвав

 Person.call(this, name)
  

Есть очень хороший JavaScript-туториал по MDN, который очень помог мне разобраться в работе с прототипом:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript

Взгляните на главу «Пользовательские объекты». Думаю, я не смог бы объяснить это лучше.

Ответ №2:

Во втором фрагменте кода, если вы немного изменили одну строку

 Employee.prototype = new Person('bob');
  

код бы сработал (сотрудник по-прежнему был «откровенным»)

Проблема в вашем конструкторе

 function Person(name) {
    // create member 'init' ONLY if an argument was passed to the constructor
    if (arguments.length > 0)
        this.init = function(name) {
            this.name = name;
        }
}
  

Как было сказано в другом ответе, изменение prototype Person изменяет все экземпляры класса Person и

 Person.prototype.init = function(name) { ... }
  

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

Строка

 Employee.prototype = new Person();
  

утверждает, что каждый экземпляр класса Employee будет иметь все члены, у которых есть объект с правой стороны. В данном случае — новый экземпляр Person

Кстати, не рекомендуется определять члены функции внутри конструкторов классов, потому что при каждом вызове конструктора потребуется создавать новую функцию. В то время как в случае модификации прототипа функция создается один раз и используется совместно со всеми экземплярами объекта.