TypeScript-konstruktører som returnerer et objekt erstatter implisitt verdien av `this` for alle kallere av `super(...)`?


Jeg prøver å forstå en setning i håndboken:

I ES2015, konstruktører som returnerer et objekt implisitt erstatter verdien av this for alle kallere av super(...). Det er nødvendig for generert konstruktørkode å fange opp enhver potensiell returverdi fra super(...) og erstatte den med this.

Hele linjen er vag for meg. Kan noen forklare hva som skjedde her?

Svar #1

Den super "funksjonskallet" er merkelig. For vanlige klasser som ikke returnerer objekter, er this bare den nåværende instansen av klassen som blir konstruert. Kallet til super() opererer bare på den samme this, og dermed er det endelige konstruerte objektet en instans av subklassen:

class Foo {
    a = 10;
    constructor() { }
}

class Bar extends Foo {
    z: number;
    constructor() {
        super();
        this.z = 1;
    }
}

const b = new Bar();
console.log(b); // Bar: {a: 10, z: 1}
console.log(b instanceof Bar); // true

Men hvis superklassen returnerer en verdi fra konstruktøren sin, blir på en eller annen måte this i subklassen den verdien. Det gjør at etterfølgende referanser til this kan referere til det samme objektet som superklassen returnerer. Så subklassen oppfører seg "normalt" bortsett fra at det konstruerte objektet faktisk ikke er en instans av klassen:

class Foo {
    constructor() {
        return { a: 10 };
    }
}

class Bar extends Foo {
    z: number;
    constructor() {
        super();
        this.z = 1;
    }
}

const b = new Bar();
console.log(b); // {a: 10, z: 1}
console.log(b instanceof Bar); // false

Det betyr at kall til super() må se ut som «kall overklassekonstruktøren som en funksjon, på en måte, og se om den returnerer noe». Hvis det gjør det, så tilordne resultatet av den funksjonen til this. Som om du kunne skrive

this = superCtor.call(this) || this;

Men du kan ikke gjøre det! Du kan ikke tilordne til this. Men det skjer likevel, implisitt. Hvis du ser på hva som skjer når superkonstruktører kalles når kode nedgraderes til en versjon av JS før class eksisterte, vil du se noe lignende:

function Bar() {
    var _this = _super.call(this) || this;
    _this.z = 1;
    return _this;
}

Og du ser at den faktiske this har blitt erstattet med en ny _this-variabel overalt.

Lenke til kode på lekeplassen