Özel anahtar kelime ile TypeScript'teki özel alanlar arasındaki farklar nelerdir?


27

TypeScript 3.8+ sürümünde, privatebir üyeyi özel olarak işaretlemek için anahtar kelimeyi kullanma arasındaki farklar nelerdir :

class PrivateKeywordClass {
    private value = 1;
}

JavaScript için önerilen# özel alanları kullanarak :

class PrivateFieldClass {
    #value = 1;
}

Birini diğerine tercih etmeli miyim?


Yanıtlar:


43

Özel anahtar kelime

Özel anahtar kelime daktilo bir olan derleme zamanı ek açıklamadır. Derleyiciye, bir özelliğin yalnızca bu sınıf içinde erişilebilir olması gerektiğini bildirir:

class PrivateKeywordClass {
    private value = 1;
}

const obj = new PrivateKeywordClass();
obj.value // compiler error: Property 'value' is private and only accessible within class 'PrivateKeywordClass'.

Bununla birlikte, derleme zamanı kontrolü, örneğin tür bilgisini atmak suretiyle kolayca atlanabilir:

const obj = new PrivateKeywordClass();
(obj as any).value // no compile error

privateAnahtar kelime çalışma zamanında da zorlanmaz

Yayılan JavaScript

TypeScript'i JavaScript ile derlerken, privateanahtar kelime kaldırılır:

class PrivateKeywordClass {
    private value = 1;
}

Oluyor:

class PrivateKeywordClass {
    constructor() {
        this.value = 1;
    }
}

Bundan, privateanahtar kelimenin neden herhangi bir çalışma zamanı koruması sağlamadığını görebilirsiniz: oluşturulan JavaScript'te bu sadece normal bir JavaScript özelliğidir.

Özel alanlar

Özel alanlar , özelliklerin çalışma zamanında gizli tutulmasını sağlar :

class PrivateFieldClass {
    #value = 1;

    getValue() { return this.#value; }
}

const obj = new PrivateFieldClass();

// You can't access '#value' outside of class like this
obj.value === undefined // This is not the field you are looking for.
obj.getValue() === 1 // But the class itself can access the private field!

// Meanwhile, using a private field outside a class is a runtime syntax error:
obj.#value

// While trying to access the private fields of another class is 
// a runtime type error:
class Other {
    #value;

    getValue(obj) {
        return obj.#value // TypeError: Read of private field #value from an object which did not contain the field
    }
}

new Other().getValue(new PrivateKeywordClass());

TypeScript, sınıf dışında özel bir alan kullanmayı denerseniz de derleme zamanı hatası verir:

Özel bir alana erişim hatası

Özel alanlar bir JavaScript teklifinden gelir ve normal JavaScript'te de çalışır.

Yayılan JavaScript

TypeScript'te özel alanlar kullanıyorsanız ve çıktınız için JavaScript'in eski sürümlerini es6veya es2018gibi hedeflerseniz, TypeScript özel alanların çalışma zamanı davranışını taklit eden kod üretmeye çalışır

class PrivateFieldClass {
    constructor() {
        _x.set(this, 1);
    }
}
_x = new WeakMap();

Eğer hedefliyorsanız esnext, typescript özel alan yayacaktır:

class PrivateFieldClass {
    constructor() {
        this.#x = 1;
    }
    #x;
}

Hangisini kullanmalıyım?

Neyi başarmaya çalıştığınıza bağlıdır.

privateAnahtar kelime Güzel bir default. Başarmak için tasarlandığını başarır ve yıllardır TypeScript geliştiricileri tarafından başarıyla kullanılmaktadır. Mevcut bir kod tabanınız varsa, özel alanları kullanmak için tüm kodunuzu değiştirmenize gerek yoktur. Bu, özellikle hedefleme yapmıyorsanız doğrudur esnext, çünkü TS'nin özel alanlar için yaydığı JS'nin performans etkisi olabilir. Özel alanların privateanahtar kelimeden başka ince ancak önemli farklılıklar olduğunu da unutmayın

Ancak, çalışma zamanı özelliğini zorunlu kılmanız veya esnextJavaScript çıktısı almanız gerekiyorsa, özel alanları kullanmanız gerekir.

Ayrıca, özel alanlar JavaScript / TypeScript ekosistemlerinde daha yaygın hale geldikçe, birini veya diğerini kullanma konusundaki kuruluş / topluluk sözleşmelerinin de gelişeceğini unutmayın.

Notun diğer farklılıkları

  • Özel alanlar Object.getOwnPropertyNamesve benzeri yöntemlerle döndürülmez

  • Özel alanlar tarafından serileştirilmedi JSON.stringify

  • Miras çevresinde son derece önemli durumlar vardır.

    Örneğin TypeScript, üst sınıftaki özel özellikle aynı ada sahip bir alt sınıfta özel özellik bildirilmesini yasaklar.

    class Base {
        private value = 1;
    }
    
    class Sub extends Base {
        private value = 2; // Compile error:
    }

    Özel alanlar için bu geçerli değildir:

    class Base {
        #value = 1;
    }
    
    class Sub extends Base {
        #value = 2; // Not an error
    }
  • Bir privatebir başlatıcısı almadan anahtar kelime özel mülkiyet yayılan JavaScript mal beyanında oluşturmaz:

    class PrivateKeywordClass {
        private value?: string;
        getValue() { return this.value; }
    }

    Derleme:

    class PrivateKeywordClass {
        getValue() { return this.value; }
    }

    Özel alanlar her zaman bir mülkiyet bildirimi oluştururken:

    class PrivateKeywordClass {
        #value?: string;
        getValue() { return this.#value; }
    }

    Derleme (hedefleme sırasında esnext):

    class PrivateKeywordClass {
        #value;
        getValue() { return this.#value; }
    }

Daha fazla okuma:


4

Kullanım örnekleri: #-Özel alanlar

Önsöz:

Derleme zamanı ve çalışma zamanı gizliliği

#-özel alanlar derleme zamanı ve çalışma zamanı gizliliği sağlar, bu da "hacklenemez". Bir üyeye sınıf gövdesinin dışından herhangi bir şekilde doğrudan erişimi engelleyen bir mekanizmadır .

class A {
    #a: number;
    constructor(a: number) {
        this.#a = a;
    }
}

let foo: A = new A(42);
foo.#a; // error, not allowed outside class bodies
(foo as any).#bar; // still nope.

Güvenli sınıf mirası

#-Özel alanlar benzersiz bir kapsam alır. Sınıf hiyerarşileri, eşit adlara sahip özel mülklerin üzerine yazılmasına gerek kalmadan uygulanabilir.

class A { 
    #a = "a";
    fnA() { return this.#a; }
}

class B extends A {
    #a = "b"; 
    fnB() { return this.#a; }
}

const b = new B();
b.fnA(); // returns "a" ; unique property #a in A is still retained
b.fnB(); // returns "b"

TS derleyici, privateözelliklerin üzerine yazılma tehlikesi olduğunda neyse ki bir hata yayar ( bu örneğe bakın ). Ancak derleme zamanı özelliğinin doğası gereği, derleme hataları göz ardı edildiğinde ve / veya yayılan JS kodu kullanıldığında, çalışma zamanında her şey hala mümkündür.

Harici kütüphaneler

Kütüphane yazarları, #istemcilerde bir değişikliğe neden olmadan özel tanımlayıcıları yeniden düzenleyebilir. Diğer taraftaki kütüphane kullanıcıları dahili alanlara erişimden korunur.

JS API #- özel alanları atlar

Yerleşik JS işlevleri ve yöntemleri #-grivate alanları yok sayar. Bu, çalışma zamanında daha öngörülebilir bir özellik seçimine neden olabilir. Örnekler: Object.keys, Object.entries, JSON.stringify, for..indöngü ve diğerleri ( kod örneği ; ayrıca Matt Bierner görelim cevabı ):

class Foo {
    #bar = 42;
    baz = "huhu";
}

Object.keys(new Foo()); // [ "baz" ]

Kullanım örnekleri: privateanahtar kelime

Önsöz:

Dahili sınıf API'sına ve durumuna erişim (yalnızca derleme zamanı gizliliği)

privatebir sınıfın üyeleri çalışma zamanında geleneksel özelliklerdir. Bu esnekliği sınıf dahili API'sine veya durumuna dışarıdan erişmek için kullanabiliriz. Derleyici kontrollerini sağlamak için, tür iddiaları, dinamik özellik erişimi gibi mekanizmalar veya @ts-ignorediğerleri arasında kullanılabilir.

Tür onaylı ( as/ <>) ve anyyazılan değişken atamalı örnek:

class A { 
    constructor(private a: number) { }
}

const a = new A(10);
a.a; // TS compile error
(a as any).a; // works
const casted: any = a; casted.a // works

TS private, kaçış kapağı olan bir üyenin dinamik mülk erişimine bile izin verir :

class C {
  private foo = 10;
}

const res = new C()["foo"]; // 10, res has type number

Özel erişim nerede mantıklı olabilir? (1) birim testleri, (2) hata ayıklama / günlüğe kaydetme durumları veya (3) proje iç sınıflarıyla birlikte diğer ileri durum senaryoları (açık uçlu liste).

İç değişkenlere erişim biraz çelişkilidir - aksi takdirde onları privateilk etapta yapmazdınız . Bir örnek vermek gerekirse, birim testlerin, özel alanların uygulama ayrıntısı olarak gizlendiği siyah / gri kutular olması gerekir. Ancak pratikte, durumdan duruma doğru geçerli yaklaşımlar olabilir.

Tüm ES ortamlarında kullanılabilir

TS privatedeğiştiricileri tüm ES hedefleriyle kullanılabilir. #-Özel alanlar yalnızca target ES2015/ ES6veya üstü için kullanılabilir . ES6 + ' WeakMapda dahili olarak alt düzey uygulama olarak kullanılır ( buraya bakın ). Yerel #-özel alanlar şu anda zorunludur target esnext.

Tutarlılık ve uyumluluk

Ekipler private, tek erişim değiştirici olarak kullanımını zorlamak için kodlama yönergelerini ve linter kurallarını kullanabilir . Bu kısıtlama, tutarlılığa yardımcı olabilir ve #-grivate alan notasyonu ile geriye dönük uyumlu bir şekilde karışıklığı önleyebilir .

Gerekirse, parametre özellikleri (yapıcı ataması kısayolu) bir gösteri durdurucusudur. Yalnızca privateanahtar kelime ile kullanılabilirler ve bunları -gizli alanlar için uygulamak için henüz bir plan yoktur# .

Diğer sebepler

  • privatebazı dengeleme durumlarında daha iyi çalışma zamanı performansı sağlayabilir ( buraya bakın ).
  • TS'de şu ana kadar zor özel sınıf yöntemleri mevcut değil.
  • Bazı insanlar privategösterim daha iyi anahtar kelime 😊.

İkisine de not

Her iki yaklaşım da derleme zamanında bir tür nominal veya markalı tür oluşturur.

class A1 { private a = 0; }
class A2 { private a = 42; }

const a: A1 = new A2(); 
// error: "separate declarations of a private property 'a'"
// same with hard private fields

Ayrıca, her ikisi de çapraz örnek erişimine izin verir: sınıf örneği Adiğer Aörneklerin özel üyelerine erişebilir :

class A {
    private a = 0;
    method(arg: A) {
        console.log(arg.a); // works
    }
}

Kaynaklar

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.