@netW0rm

Логично ли данное ООП поведение в javascript и отличается ли оно от c++ и java?

https://jsfiddle.net/k3wrstLy
class A {
  foo() {
    this.bar()
  }
  bar() {
    console.log('bar')
  }
}

class B extends A {
  bar() {  	
    super.foo()
    console.log('bar 2')
  }
}

let b = new B

b.bar() // Uncaught RangeError: Maximum call stack size exceeded

Я ожидаю, что в методе bar() класса B при вызове super.foo() будет вызван метод foo() класса A, в котором будет вызван метод bar() класса А, но вызывается метод bar() класса B и мы получаем ошибку Uncaught RangeError: Maximum call stack size exceeded
Логично ли такое поведение с точки зрения ООП, в c++ и java происходит так же?

UPD:
Спасибо комментаторам, разобрался.
Чтобы получилось так как я хочу, нужно заменить вызов super.foo() на A.prototype.foo()
  • Вопрос задан
  • 519 просмотров
Решения вопроса 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега JavaScript
Всё дело в том, что this в A.foo ссылается не на A, а на инстанс B. А поиск метода идёт по цепочке прототипов, начиная сверху, поэтому до A.bar никогда не доходит.
Рассуждать, логично это или нет, бессмысленно - это просто так и нужно принять такое поведение, понять его и использовать.

И нет, в Java и C++ поведение не такое. Вообще, в javascript наследование прототипное и есть закидоны особенности с контекстом вызова, поэтому привычное из других языков понимание ООП в нём не всегда работает.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
k12th
@k12th
console.log(`You're pulling my leg, right?`);
Вы так говорите, будто существует какое-то эталонное ООП, хранящееся в палате мер и весов в Париже. ООП -- это несколько принципов, которые можно трактовать по-разному (Алан Кей, ЕМНИП, сказал: "Я изобрел термин ООП, но я не имел ввиду C++"). В JS вообще классов не было до недавнего времени, да и сейчас это тонкий слой синтаксической сахарной пудры над прототипами.

Когда мы в JS обращаемся к свойству объекта, то движок сначала ищет это свойство в самом объекте. Если свойство не найдено, то идем в объект, который записан как прототип этого объекта, и ищем в нем. Повторяем этот шаг, пока не найдем свойство или не дойдем до Object.
Когда мы вызываем метод объекта через точку (типа b.bar()), то он выполняется в контексте этого объекта b. super.foo() пропускает первый шаг в поиске свойства, берет метод сразу из прототипа прототипа и тоже выполняет его в контексте b. А в контексте b метод bar у нас переопределяет родительский метод, поэтому у нас получается бесконечная рекурсия, которая насильно обрывается движком.

Что должно быть в Java/C++ я вам не подскажу, к сожалению. Возможно, там будет поведение, которое вы ожидаете.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы