Доступ к члену базового класса


118

См. Пример наследования с игровой площадки на сайте TypeScript:

class Animal {
  public name;
  constructor(name) {
    this.name = name;
  }
  move(meters) {
    alert(this.name + " moved " + meters + "m.");
  }
}

class Snake extends Animal {
  constructor(name) {
    super(name);
  }
  move() {
    alert("Slithering...");
    super.move(5);
  }
}

class Horse extends Animal {
  constructor(name) {
    super(name);
  }
  move() {
    alert(super.name + " is Galloping...");
    super.move(45);
  }
}

var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

Я изменил одну строку кода: предупреждение в Horse.move(). Я хочу получить доступ super.name, но это просто возвращается undefined. IntelliSense предлагает мне использовать его, и TypeScript отлично компилируется, но это не работает.

Любые идеи?

Ответы:


179

Рабочий пример. Примечания ниже.

class Animal {
    constructor(public name) {
    }

    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    move() {
        alert(this.name + " is Slithering...");
        super.move(5);
    }
}

class Horse extends Animal {
    move() {
        alert(this.name + " is Galloping...");
        super.move(45);
    }
}

var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);
  1. Вам не нужно вручную назначать имя публичной переменной. Использование public nameв определении конструктора сделает это за вас.

  2. Вам не нужно звонить super(name)из специализированных классов.

  3. Использование this.nameработает.

Примечания по использованию super.

Более подробно это описано в разделе 4.9.2 спецификации языка.

Поведение классов, наследующихся от Animal, не отличается от поведения в других языках. Вам необходимо указать superключевое слово, чтобы избежать путаницы между специализированной функцией и функцией базового класса. Например, если вы вызвали move()или this.move()имеете дело со специализированной функцией Snakeили Horseфункцией, использование super.move()явно вызывает функцию базового класса.

Нет никакой путаницы в свойствах, поскольку они являются свойствами экземпляра. Нет разницы между super.nameи this.name- есть просто this.name. В противном случае вы могли бы создать лошадь с разными именами в зависимости от того, принадлежали вы к специализированному классу или базовому классу.


Отличный ответ, и спасибо за ссылку на спецификацию языка. Известна ли вам какая-либо документация о том, почему, например, средства доступа к свойствам базового класса не виртуализированы и не доступны через переопределяющие средства доступа в производном классе (как методы)?
— Дэвид Кучча

Раздел 4.8 охватывает все, что было записано на сегодняшний день - это скорее «это поведение», а не «вот почему».
— Fenton

3
Спасибо, Стив Фентон. Я также случайно наткнулся на подобное обсуждение здесь: typescript.codeplex.com/discussions/418349 . Кажется, дисбаланс в языке; Я предполагаю, что было принято решение сохранить простоту генерируемого JavaScript, в отличие от вспомогательных методов «обходного пути», чтобы компенсировать отсутствие поддержки JavaScript.
— Дэвид Кучча

1

Вы неправильно используя superи thisключевое слово. Вот пример того, как они работают:

class Animal {
    public name: string;
    constructor(name: string) { 
        this.name = name;
    }
    move(meters: number) {
        console.log(this.name + " moved " + meters + "m.");
    }
}

class Horse extends Animal {
    move() {
        console.log(super.name + " is Galloping...");
        console.log(this.name + " is Galloping...");
        super.move(45);
    }
}

var tom: Animal = new Horse("Tommy the Palomino");

Animal.prototype.name = 'horseee'; 

tom.move(34);
// Outputs:

// horseee is Galloping...
// Tommy the Palomino is Galloping...
// Tommy the Palomino moved 45m.

Объяснение:

  1. Первые выходные данные журнала super.nameотносятся к цепочке прототипов объекта tom, а не к tomсамому объекту . Поскольку мы добавили свойство name в Animal.prototype, будет выведено Horseee.
  2. Второй вывод журнала this.name, thisключевое слово относится к самому объекту тома.
  3. Третий журнал регистрируется с использованием moveметода базового класса Animal. Этот метод вызывается из метода перемещения класса Horse с синтаксисом super.move(45);. Использование superключевого слова в этом контексте будет искать moveметод в цепочке прототипов, который находится в прототипе Animal.

Помните, что TS по-прежнему использует прототипы под капотом, classа extendsключевые слова и являются всего лишь синтаксическим сахаром по сравнению с прототипным наследованием.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.