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

Посмотрите пример наследования с игровой площадки на сайте 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 компилируется нормально, но это не работает.

Есть идеи?

Ответ 1

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

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. В противном случае вы могли бы создать Лошадь с разными именами в зависимости от того, были ли вы в специализированном классе или в базовом классе.

Ответ 2

Вы неправильно используете 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 Self. Поскольку мы добавили свойство name в Animal.prototype, будет Animal.prototype horseee.
  2. Второй журнал выводит this.name, ключевое слово this относится к самому объекту Tom.
  3. Третий журнал регистрируется с помощью метода move базового класса Animal. Этот метод вызывается из метода перемещения класса Horse с синтаксисом super.move(45); , Использование ключевого слова super в этом контексте будет искать метод move в цепочке прототипов, который находится в прототипе Animal.

Помните, что TS все еще использует прототипы под капотом и class и extends ключевые слова как синтаксический сахар по сравнению с прототипным наследованием.