Private class fields

Właściwości klas są domyślnie publiczne i mogą być wywoływane i modyfikowane poza klasą. Istnieje jednak funkcjonalność eksperymentalna pozwalająca na zdefiniowanie pól prywatnych klasy przy użyciu # przed nazwą pola.

Składnia

class ClassWithPrivateField {   
  #privateField
}

class ClassWithPrivateMethod {   
  #privateMethod() {     
    return 'hello world'
  }
}

class ClassWithPrivateStaticField {   
  static #PRIVATE_STATIC_FIELD
}

Przykłady

Prywatne pola statyczne

Pola prywatne są dostępne z poziomu konstruktora klasy ze środka ciała klasy.

Prywatne pola statyczne są tylko dostępne z poziomu statycznych metod. 

class ClassWithPrivateStaticField {
  static #PRIVATE_STATIC_FIELD

  static publicStaticMethod() {
    ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42
    return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD
  }
}

console.assert(ClassWithPrivateStaticField.publicStaticMethod() === 42)

Prywatne pola statyczne są dodawane do konstruktora klasy podczas wykonywania klasy.

Tylko klasa, która definiuje prywatne pola statyczne, może mieć do nich dostęp.

Może to prowadzić to nieoczekiwanego zachowania podczas używania this.

class BaseClassWithPrivateStaticField {
  static #PRIVATE_STATIC_FIELD

  static basePublicStaticMethod() {
    this.#PRIVATE_STATIC_FIELD = 42
    return this.#PRIVATE_STATIC_FIELD
  }
}

class SubClass extends BaseClassWithPrivateStaticField { }

let error = null

try {
  SubClass.basePublicStaticMethod()
} catch(e) { error = e}

console.assert(error instanceof TypeError)

Prywatne pola instancji

Prywatne pola instancji są deklarowane przy użyciu # names ("hash names"), czyli nazw poprzedzonych #. Znak # jest częścią nazwy. Jest używany do deklaracji i dostępu do właściwości.

Enkapsulacja jest wymuszona przez język. Próba dostępu do prywatnego pola poza klasą wygeneruje błąd Syntax Error.

class ClassWithPrivateField {
  #privateField
  
  constructor() {
    this.#privateField = 42
    this.#randomField = 444 // Syntax error
  }
}

const instance = new ClassWithPrivateField()
instance.#privateField === 42 // Syntax error

Prywatne metody

Prywatne metody statyczne

Podobnie jak ich publiczne odpowiedniki, prywatne metody statyczne są wywoływane przez samą klasę, a nie jej instancje. Podobnie jak pola prywatne, są dostępne tylko z poziomu ciała klasy.

class ClassWithPrivateStaticMethod {
    static #privateStaticMethod() {
        return 42
    }

    static publicStaticMethod1() {
        return ClassWithPrivateStaticMethod.#privateStaticMethod();
    }

    static publicStaticMethod2() {
        return this.#privateStaticMethod();
    }
}

console.assert(ClassWithPrivateStaticMethod.publicStaticMethod1() === 42);
console.assert(ClassWithPrivateStaticMethod.publicStaticMethod2() === 42);

Może to prowadzić do nieoczekiwanego zachowania przy używaniu this. W poniższym przykładzie this odnosi się do klasy Derived (a nie klasy Base) podczas wywołania metody Derived.publicStaticMethod2(), co powoduje błąd.

class Base {
    static #privateStaticMethod() {
        return 42;
    }
    static publicStaticMethod1() {
        return Base.#privateStaticMethod();
    }
    static publicStaticMethod2() {
        return this.#privateStaticMethod();
    }
}

class Derived extends Base {}

console.log(Derived.publicStaticMethod1()); // 42
console.log(Derived.publicStaticMethod2()); // TypeError

Prywatne metody instancji

Prywatne metody instancji to metody dostępne dla instancji klasy, które mają podobne ograniczenia co prywatne pola instancji.

class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world'
  }

  getPrivateMessage() {
      return this.#privateMethod()
  }
}

const instance = new ClassWithPrivateMethod()
console.log(instance.getPrivateMessage())
// expected output: "hello worl​d"

Prywatne metody mogą używać async lub być generatorami. Możliwe jest również tworzenie prywatnych getter'ów i setter'ów:

class ClassWithPrivateAccessor {
  #message

  get #decoratedMessage() {
    return `✨${this.#message}✨`
  }
  set #decoratedMessage(msg) {
    this.#message = msg
  }

  constructor() {
    this.#decoratedMessage = 'hello world'
    console.log(this.#decoratedMessage)
  }
}

new ClassWithPrivateAccessor();
// expected output: "✨hello worl​d✨"

Specyfikacje

Specyfikacja
Public and private instance fields
The definition of 'FieldDefinition' in that specification.

Kompatybilność

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Private class fieldsChrome Full support 74Edge Full support 79Firefox No support NoIE No support NoOpera Full support 62Safari Full support 14WebView Android Full support 74Chrome Android Full support 74Firefox Android No support NoOpera Android Full support 53Safari iOS Full support 14Samsung Internet Android No support Nonodejs Full support 12.0.0

Legend

Full support  
Full support
No support  
No support

Zobacz też