Как ES6 классы влияют на контекст исполнения в JavaScript?

Почему контекст ломается у ClassC при вызове this.#methidC() из метода init()? Считаю, что это может быть багом, поскольку не позволяет нормально работать с приватными методами внутри одного класса. Можете ли вы указать, где именно в спецификации описано такое поведение или это действительно баг?

class ClassA {
    constructor(){
        this.#methodA();
        this.init();
    }
    
    init(){
    
    }

    #methodA(){
        console.log('in ClassA.#methodA');
    }
}
const a = new ClassA(); // все отлично





class ClassB extends ClassA {
    constructor(){
        super();
        this.#methodB();
    }
    
    #methodB(){
        console.log('in ClassB.#methodB');
    }
}
const b = new ClassB(); // все отлично





class ClassC extends ClassA {
    init(){
        this.#methodC(); 

    }
    
    #methodC(){
        console.log('in ClassC.#methodC');
    }
}
const c = new ClassC(); // this.#methodC(); TypeError: Receiver must be an instance of class ClassC
  • 30 сентября 2023 г. 2:07
Ответы на вопрос 2
ES6 классы влияют на контекст исполнения в JavaScript в том смысле, что они автоматически привязывают методы класса к экземпляру класса, то есть контекстом исполнения становится сам экземпляр класса. Это означает, что при вызове метода класса через this, он будет иметь доступ к свойствам и методам этого экземпляра.

Проблема с контекстом исполнения в вашем примере возникает из-за использования приватных методов (методов, начинающихся с #) внутри класса. Приватные методы доступны только внутри класса, но не могут быть вызваны извне класса или его экземпляров.

В классе ClassC метод #methodC() является приватным методом. Когда вы вызываете this.#methodC() из метода init(), это нарушает правила использования приватных методов, поскольку при вызове метода #methodC() контекст исполнения должен быть экземпляром класса ClassC, но в данном случае он является экземпляром класса ClassA.

Это является согласующимся поведением согласно спецификации ECMAScript, и здесь нет никакого бага. Приватные методы могут вызываться только из того же класса, из которого они были объявлены.

Если вам нужно вызвать приватный метод из другого метода класса, вы можете объявить его как обычный метод без использования символа #.
При создании экземпляра классаClassAвызывается конструктор этого класса, который в свою очередь вызывает методinit. Так как в классеClassСметодinitопределен, именно он будет вызываться вначале. Это происходит из-за прототипного наследования.
Похожие вопросы