Perché in JavaScript è (super .__ proto__ === this .__ proto__) vero?


10

Sembra che nelle classi JavaScript (ES6) super.__proto__ === this.__proto__.

Puoi spiegare perché è così? Il comportamento sembra coerente su diversi browser, quindi sospetto che questo sia specificato da qualche parte nelle specifiche.

Considera il seguente codice:

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();

Mi sarei aspettato che super.__proto__.myFunc();avrebbe chiamato la funzione myFunc()di classe Level1e quella super.__proto__ !== this.__proto__. Invece in super.__proto__.myFunc();realtà chiama myFunc()di classe Level3(chiama se stesso) e quindi nella seconda chiamata chiama myFunc()di classe Level2. Ciò è perfettamente comprensibile se super.__proto__ === this.__proto__dimostra il codice.

Puoi spiegare il motivo per cui super.__proto__ === this.__proto__in questo esempio? Se possibile, fornire anche riferimenti alla sezione pertinente delle specifiche.

Risposte:


6

Object.prototype.__proto__è una proprietà con un getter [1] . Funziona sul suo thisvalore. Non esiste un superoggetto reale per essere un thisvalore (non si può scrivere Object.getPrototypeOf(super)), solo un supermodo per cercare le proprietà, quindi this.__proto__e super.__proto__significare la stessa cosa purché __proto__non sia anche definito in alcun punto inferiore della catena del prototipo.

Confrontare:

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__'));


Ho già sospettato che ciò avesse a che fare con l' __proto__essere effettivamente funzioni di accesso Object.prototypee operare sul loro thisvalore. Ma non potrei immaginare che in superrealtà è stato specificato per funzionare in questo modo. Pensavo di superessere approssimativamente equivalente a this.__proto__.__proto__, quindi super.__proto__sarebbe stato equivalente a quello this.__proto__.__proto__.__proto__che avrebbe mostrato il comportamento che mi aspettavo. Sai, dove nelle specifiche è specificato il comportamento esatto super?
Jens Moser,

@JensMoser: Lo troverò tra un po ', ma immagino usi normali super, come super.setFoo('bar'). Non vorresti che operasse su un prototipo anziché sull'istanza.
Ry-

@georg So che __proto__è una proprietà accessor su Object.prototype. Quando ho chiesto un riferimento alla specifica, intendevo un riferimento all'esatto comportamento della superparola chiave in combinazione con __proto__. Vedi il mio commento precedente.
Jens Moser,

@ Ry- Sì, ho semplificato un po '. La mia esatta comprensione di super.setFoo('bar')sarebbe equivalente this.__proto__.__proto__.setFoo.call(this, 'bar'). Quindi, superinvoca automaticamente le funzioni con il corretto this.
Jens Moser,

1
@JensMoser super.__proto__(in quel metodo della Level3classe) è esattamente equivalente aReflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Bergi l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.