Подтвердить что ты не робот

Вызовите родительскую функцию, которая переопределяется дочерним элементом в цепочке конструктора в JavaScript (ES6)

Я столкнулся с проблемой ниже с JavaScript (ES6)

class A{
  constructor(){
    this.foo();
  }
  foo(){
    console.log("foo in A is called");
  }
}

class B extends A{
  constructor(){
    super();
    this.foo();
  }
  foo(){
    console.log("foo in B is called");
  }
}

Я ожидаю

foo in A is called
foo in B is called

Но на самом деле это

foo in B is called
foo in B is called

Я знаю, что могу разрешить это, просто добавив super.foo() в функцию класса f B

class B extends A{
  constructor(){
    super();
    this.foo();
  }
  foo(){
    super.foo() // add this line
    console.log("foo in B is called");
  }
}

Но представьте себе подобный сценарий:

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

class B extends A{
  constructor(){
    super();
    this.initBar();
  }
  foo(){
    super.foo();
    this.bar.run(); //undefined
    console.log("foo in B is called");
  }
  initBar(){
    this.bar.run = function(){
      console.log("bar is running");
    };
  }
}

Кажется, что this все еще указывает на дочерний элемент B при построении в родительском A. Поэтому я не могу связаться с родителем A foo.

Как мне сделать this для вызова функции родительской версии, которая переопределяется дочерним элементом в цепочке конструктора?

Или есть ли лучшее решение, когда дело доходит до такого сценария?

Edit

Итак, после прочтения ответов главный вопрос становится -

Не рекомендуется ли помещать initialize helpers или setter functions в конструктор в JavaScript, так как у детей есть возможность переопределить их?

Прояснить ситуацию более четко: (извините за мой предыдущий плохой пример:()

class A{
  constructor(name){
    this.setName(name);
  }
  setName(name){
    this._name = name;
  }
}

class B extends A{
  constructor(name){
    super(name);
    this._div = document.createElementById("div");
  }
  setName(name){
    super.setName(name);
    this._div.appendChild(document.createTextNode(name));
  }
}

new B("foo")

this._div будет undefined.

Это плохая идея, так как ребенок сможет переопределить функцию?

class A{
  constructor(name){
    this.setName(name); // Is it bad?
  }
  ...
}

Поэтому я не должен использовать initialize helpers или setter functions в конструкторе, как в Java, С++...?

Должен ли я вручную вызывать такие вещи new A().init(), чтобы помочь мне инициализировать вещи?

4b9b3361

Ответ 1

Кажется, вы работаете с неправильным пониманием того, что есть два объекта A и B, когда вы находитесь в конструкторе производного класса B. Это совсем не так. Существует один и только один объект. Оба A и B вносят свойства и методы в один объект. Значение this будет таким же в конструкторе для B, что и в конструкторе для A при создании объекта класса B.

Синтаксис класса ES6 - это просто сахар над методом ES5 использования прототипов для типов объектов, и, по сути, прототип все еще используется под обложками. Таким образом, когда вы определяете метод foo в производном классе, как вы это делаете в классе B, он все еще назначает прототипу, и это присвоение переопределяет любой метод с тем же именем, который уже может существовать на прототипе, который появился из родительское определение. Вот почему this.foo() относится к версии класса B foo. Если вы хотите достичь версии класса A foo, тогда вы укажете вручную, используя super, как вы уже знаете.

Что касается ваших конкретных вопросов:

Кажется, что это все еще указывает на ребенка B при построении в parent A. Вот почему я не могу связаться с родителем A foo.

дочерний B и родительский A не являются отдельными объектами. Существует один объект, который содержит как родительские, так и дочерние B ссылки. родительский метод A или дочерний B или конструкторы будут видеть то же самое значение this.

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

Вы используете super для ссылки на родительские методы напрямую, как вы уже знаете.

Или есть ли лучшее решение, когда дело доходит до такого сценария?

super является решением.


FYI, это довольно хорошее обсуждение классов ES6, в том числе, как работает super: Классы в ECMAScript 6 (окончательная семантика). Раздел 4.4 кажется особенно актуальным для вашего вопроса/понимания.