Чому в JavaScript справжнє (супер .__ прото__ === це .__ прото__)?


10

Здається, що в JavaScript (ES6) класи super.__proto__ === this.__proto__.

Чи можете ви пояснити, чому це так? Поведінка здається послідовною у різних браузерах, тому я підозрюю, що це вказано десь у специфікації.

Розглянемо наступний код:

class Level1 {
    myFunc() {
        console.log('Level1');
    }
}

class Level2 extends Level1 {
    myFunc() {
        console.log('Level2');
    }
}

class Level3 extends Level2 {
    myFunc() {
        console.log('Level3 BEGIN ' + Math.random()); 
        super.__proto__.myFunc();
        console.log(super.__proto__ === this.__proto__);
        console.log('Level3 END'); 
    }
}

const foo = new Level3();
foo.myFunc();

Я б очікував, що це super.__proto__.myFunc();буде називати функцію myFunc()класу Level1і це super.__proto__ !== this.__proto__. Натомість super.__proto__.myFunc();насправді дзвінки myFunc()класу Level3(він називає себе), а потім на другому виклику він називає myFunc()клас Level2. Це цілком зрозуміло, якщо super.__proto__ === this.__proto__це демонструє код.

Чи можете ви пояснити причину, чому super.__proto__ === this.__proto__в цьому прикладі? Якщо можливо, будь ласка, надайте посилання на відповідний розділ специфікації.

Відповіді:


6

Object.prototype.__proto__є власністю з геттером [1] . Він діє за своєю thisцінністю. Там немає ніякого фактичного superоб'єкта бути thisзначення (ви не могли б написати Object.getPrototypeOf(super)), просто superспосіб пошуку властивостей, так this.__proto__і super.__proto__означає те ж саме, поки __proto__також не визначене в будь-якому місці нижче по ланцюжку прототипів.

Порівняйте:

class Parent {
    get notProto() {
        return this instanceof Child;
    }
}

class Child extends Parent {
    test() {
        console.log(super.notProto);
    }
}

new Child().test();

// bonus: [1]
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));


Я вже підозрював, що це має щось спільне з тим, що __proto__насправді функціонують аксесуари Object.prototypeта працюють на їх thisзначення. Але я просто не superміг уявити, що насправді було визначено для роботи таким чином. Я думав, superщо це приблизно рівнозначно this.__proto__.__proto__, тому super.__proto__було б рівнозначно тому, this.__proto__.__proto__.__proto__що проявило б поведінку, на яку я очікував. Чи знаєте ви, де в специфікації superвказана точна поведінка ?
Йенс Мозер

@JensMoser: Я знайду його трохи, але уявіть собі нормальне використання super, як super.setFoo('bar'). Ви не хочете, щоб це працювало на прототипі замість екземпляра.
Ри-

@georg Я знаю, що __proto__це властивість аксесуара Object.prototype. Коли я попросив посилання на специфікацію, я мав на увазі посилання на точну поведінку superключового слова в поєднанні з __proto__. Дивіться мій попередній коментар.
Єнс Мозер

@ Ry- Так, я трохи спростив. Моє точне розуміння super.setFoo('bar')було б, що це рівнозначно this.__proto__.__proto__.setFoo.call(this, 'bar'). Отже, superавтоматично викликає функції з правильним this.
Йенс Мозер

1
@JensMoser super.__proto__(в цьому способі Level3класу) в точності еквівалентноReflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Берги
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.