Невозможно использовать свойства дочернего класса в конструкторе родительского класса через свойства преобразования класса Babel.

При расширении родительского класса и объявлении свойств дочернего класса с помощью подключаемого модуля Babel «transform-class-properties» любые свойства класса дочернего класса недоступны через метод конструктора родительского класса.

class One {

    internal = 1;

    constructor() {
        console.log('constructor internal', this.internal);
    }

}

class Two extends One {

    internal = 2;

}

new Two();

В приведенном выше примере на консоль будет выводиться «внутренний конструктор 1». При взгляде на скомпилированный код становится очевидным, почему сначала выполняется родительский класс, а затем результирующий объект интегрируется с дочерним классом.

Извиняюсь, если это задумано, но это смутило меня, поскольку следующий код работает так, как я ожидаю, в методах, не являющихся конструкторами (поэтому метод boot() ссылается на значение свойства «внутреннее» дочернего класса):

class One {

    internal = 1;

    constructor() {
        console.log('constructor internal', this.internal);
    }

    boot() {
        console.log('boot internal', this.internal);
    }

}

class Two extends One {

    internal = 2;

    constructor() {
            super();

            this.boot();
    }

}

new Two();

Таким образом, даже при вызове метода, объявленного в родительском классе, он наследует свойства дочернего класса. Это просто методы конструктора, которые, по-видимому, ведут себя не так, как ожидалось (по крайней мере, для меня - опять же, извиняюсь, если это неправильно интерпретировано, но на соответствующей странице Babel нет никаких предостережений.)

Спасибо.


person Richard Nicholls    schedule 23.08.2016    source источник
comment
Да, это по дизайну. Не обращайтесь к перезаписываемым свойствам (или методам) в конструкторе. Не выполняйте побочные эффекты в конструкторе, только инициализируйте свойства.   -  person Bergi    schedule 23.08.2016
comment
В чем именно заключается ваш вопрос? Кажется, вы уже нашли решение (хотя вам лучше не вызывать boot из конструктора, а делать new Two().boot())   -  person Bergi    schedule 23.08.2016
comment
Поиграв с этим еще немного, я нашел 2 способа обойти эту проблему, но мне все еще очень интересно узнать, можно ли получить доступ к дочерним свойствам, не делая следующее: # 1 Статические свойства class One { static a = 1; конструктор() { console.log(this.constructor.a); } } class Two extends One { static a= 2; } новый Два(); #2 Методы получения class One { get a() { return 1 }; конструктор() { console.log(this.a); } } class Two extends One { get a() { return 2; } } новый Два();   -  person Richard Nicholls    schedule 23.08.2016
comment
Нет, родительский конструктор всегда выполняется первым, прежде чем вы сможете что-либо сделать с экземпляром. Однако вы можете попробовать передать значение в качестве аргумента.   -  person Bergi    schedule 23.08.2016
comment
Спасибо, Берги, и извините за форматирование (я все еще писал это, когда вы уже ответили дважды!). Проблема была просто в попытке написать элегантный код для определенной ситуации. Я буду полагаться на один из менее элегантных примеров, которые я предоставил, или, что, вероятно, будет разумнее, вместо этого использовать фабрику. Спасибо за ваш быстрый ответ!   -  person Richard Nicholls    schedule 23.08.2016
comment
Забавно, я нашел этот пример на странице документа preact preactjs.com/guide/extending-component. это, кажется, использует ту самую функцию, о которой вы говорите. Однако это не работает, или, возможно, ему нужна какая-то особая конфигурация Babel. См. класс MixedComponent внизу этой страницы.   -  person cipak    schedule 19.02.2019


Ответы (2)


Я думаю, что это естественно. Если вы хотите переопределить начальное значение свойства родительского класса, вы должны сделать это в конструкторе производного класса.

class Two extends One {

    constructor() {
        // Call parent constructor.
        super();
        // Override here.
        this.internal = 2;
    }

}

Надеюсь, поможет. Удачного кодирования (:

person Jigarius    schedule 23.08.2016
comment
Он уже делает это эффективно. Ему просто интересно, почему родительский конструктор не видит перезаписанное значение. - person Bergi; 23.08.2016
comment
Спасибо, Джигар, я думаю, что мог бы использовать этот образец. Это очень чисто! Ваше здоровье. - person Richard Nicholls; 25.08.2016

loganfsmyth очень четко ответил на мой вопрос здесь: https://phabricator.babeljs.io/T7567 (Спасибо! )

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

Свойства класса инициализируются, когда:

  • Для базовых классов перед выполнением конструктора

  • Для дочерних классов в конце super()

и когда данный конструктор инициализирует свои привязки, он использует привязки этих классов, он ничего не знает о дочерних классах. Это означает, что ваш класс One знает, что значение должно быть 1, поэтому он устанавливает именно это.

person Richard Nicholls    schedule 23.08.2016