javascript - Varför en privat variabel i en klass behandlas som offentlig i den transpilerade koden


Jag har lagt till följande klass i TypeScript

class Person {
    private variable1;
    public varibele2;

    Person(){
        this.variable1 = 'abc';
        this.varibele2 = 'xyz'; 
    }

    public getVariable1(){
        return this.variable1;        
    }
}

Så när jag kompilerar koden med tsc, genererar det följande kod

var Person =  (function () {
    function Person() {
    }
    Person.prototype.Person = function () {
        this.variable1 = 'abc';
        this.varibele2 = 'xyz';
    };
    Person.prototype.getVariable1 = function () {
        return this.variable1;
    };
    return Person;
}());

Eftersom variable1 är privat bör det inte vara tillgängligt av obj av den klassen (vilket händer i TypeScript-koden).

Samma beteende bör ske i transpilerad ES5-kod (men händer inte).

I det transpilerade koden i exemplet ovan skapar jag ett objekt av Person

var p = new Person();
console.log(p.variable1); // undefined 
p.variable1 = 'abc1';  // setting value to variable 1 
console.log(p.variable1); // 'abc1'
console.log(p.getVariable1()); // 'abc1'

I ovanstående kod borde jag inte kunna sätta eller hämta värdet på variable1.

var p = new Person();
console.log(p.getVariable1()); // 'undefined' 
p.variable1 = 'abc1';  // setting value to variable1 
console.log(p.getVariable1()); // 'abc1'

I ovanstående kod försöker jag hämta värdet med p.getVariable1() och jag får undefined. Eftersom värdet redan är tilldelat i klassens konstruktor bör det vara tillgängligt via p.getVariable1()

var p = new Person();
console.log(p.variable2); // undefined
p.variable2 = 'xyz1'; // setting value
console.log(p.variable2);// 'xyz1'

I ovanstående kod borde Variable2 returnera 'xyz' men det gör det inte. När jag tilldelar värde till den, returnerar den.

Så beteendet hos privata och offentliga variabler är detsamma i den transpilerade koden och det är väldigt förvirrande. Det returnerar inte värdet som tilldelats i konstruktorn.

Svar #1

För att fortsätta vår diskussion från kommentarerna, här är fördelen du får av att använda offentlig vs privat:

IDE:n kommer att tala om för dig omedelbart att du gör något du inte ska göra. Om du ignorerar dessa fel kommer koden att kompileras till JavaScript och köras, men poängen är att du inte ignorerar dessa fel. När du skriver dålig kod som detta, säger TypeScript åt dig att det finns ett problem, och då kan du fixa problemet. Om du har en byggprocess kan du ställa in den så att dessa TypeScript-fel gör att bygget misslyckas, vilket tvingar dig att åtgärda problemet innan distribution.

Typescript är ett verktyg för att hjälpa dig skriva bättre javascriptkod, genom att fånga fel tidigare och enklare. Det är inte ett verktyg för att ändra hur javascript fungerar. Typescript tillhandahåller inte typkontroll vid körning, och om det är vad du letar efter, kommer du inte att hitta det. Om du behöver closures för att dölja variabler, skapa då en closure själv.

Svar #2

Först, för att svara på din huvudfråga:

Varför en privat variabel i en klass behandlas som offentlig i den transpilerade koden.

Det är sant att private-egenskaper, liksom readonly-egenskaper, transpileras till vanliga egenskaper och blir därmed "publika". Jag tror att det är för att förenkla och snabba upp transpilationen TS→JS och för att främja användningen av TypeScript överallt, där varningar eller fel genereras när man utför ogiltiga operationer på dessa typer av egenskaper: att komma åt en privat egenskap utanför klassen, omassignera en readonly-egenskap...

Men du ger exempel med väldigt konstiga beteenden. De beror inte på TypeScript-transpilering. Jag märker några problem med din klass Person som har lett till dem:

  • I ES6 och TypeScript definieras klasskonstruktorn med nyckelordet constructor, inte klassnamnet. Det är ännu mer förvirrande eftersom konstruktorn transpileras till en funktionskonstruktor med samma namn som klassen, här Person.
  • Det finns ett stavfel i den andra egenskapen: varibele2 istället för variable2. Det är därför console.log(p.variable2) inte kan skriva ut det förväntade värdet.

Genom att åtgärda dessa problem beter sig koden mer logiskt.

class Person {
    constructor(private _variable1 = 'abc', public variable2 = 'xyz') { }

    public get variable1() { return this._variable1; }
}

console.log(new Person()); // → Person { v1: [Getter], v2: "xyz", _v1: "abc", __proto__... }

Den transpilerade koden finns tillgänglig genom TypeScript-lekplatsen.

Notera: Jag föredrar en annan syntax:

  • Egenskaper deklareras direkt i konstruktorn: det är mer kompakt, det möjliggör typinferenz och vi kan ange andra initiala värden.
  • Privata variabler namnges _x för att underlätta skrivandet av en getter get x() { return this._x; }. Det är också en ofta använd JavaScript-konvention för att indikera att variabeln är avsedd att vara privat, utan ett komplext mönster för att verkligen ha en privat egenskap.

Relaterade artiklar