Tworzę klasę Javascript i chciałbym mieć publiczne pole statyczne, takie jak w Javie. To jest odpowiedni kod:
export default class Agent {
CIRCLE: 1,
SQUARE: 2,
...
Oto błąd, który otrzymuję:
line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.
Wygląda na to, że moduły ES6 na to nie pozwalają. Czy istnieje sposób na uzyskanie pożądanego zachowania, czy też muszę napisać metodę pobierającą?
javascript
ecmascript-6
class-fields
aebabis
źródło
źródło
Odpowiedzi:
Tworzysz „publiczne pole statyczne” za pomocą metody dostępu i „statycznego” słowa kluczowego:
class Agent { static get CIRCLE() { return 1; } static get SQUARE() { return 2; } } Agent.CIRCLE; // 1
Patrząc na specyfikację, 14.5 - Definicje klas - zobaczyłbyś coś podejrzanie trafnego :)
Następnie możesz przejść do punktu 14.5.14 - Semantyka środowiska uruchomieniowego: ClassDefinitionEvaluation - aby dokładnie sprawdzić, czy naprawdę działa tak, jak wygląda. Konkretnie krok 20:
IsStatic jest zdefiniowany wcześniej w 14.5.9
Tak więc
PropertyMethodDefinition
jest wywoływana z "F" (konstruktor, obiekt funkcji) jako argumentem, który z kolei tworzy metodę dostępową na tym obiekcie .Działa to już co najmniej w IETP (wersja zapoznawcza), a także w kompilatorach 6to5 i Traceur.
źródło
unsafe.enable_getters_and_setters=true
do swojego .flowconfig pod[options]
(co jest denerwujące).Istnieje propozycja skryptu Stage 3 ECMAScript nazwana „Static Class Features” autorstwa Daniela Ehrenberga i Jeffa Morrisona, która ma na celu rozwiązanie tego problemu. Wraz z propozycją „Pola klas” etapu 3 przyszły kod będzie wyglądał następująco:
class MyClass { static myStaticProp = 42; myProp = 42; myProp2 = this.myProp; myBoundFunc = () => { console.log(this.myProp); }; constructor() { console.log(MyClass.myStaticProp); // Prints '42' console.log(this.myProp); // Prints '42' this.myBoundFunc(); // Prints '42' } }
Powyższe jest równoważne z:
class MyClass { constructor() { this.myProp = 42; this.myProp2 = this.myProp; this.myBoundFunc = () => { console.log(this.myProp); }; console.log(MyClass.myStaticProp); // Prints '42' console.log(this.myProp); // Prints '42' this.myBoundFunc(); // Prints '42' } } MyClass.myStaticProp = 42;
Babel obsługuje transpiling pól klas poprzez @ babel / plugin- offer -class-properties (zawarte w ustawieniu wstępnym stage-3 ), więc możesz użyć tej funkcji, nawet jeśli twoje środowisko wykonawcze JavaScript jej nie obsługuje.
W porównaniu do rozwiązania @ kangax polegającego na deklarowaniu metody pobierającej, to rozwiązanie może być również bardziej wydajne, ponieważ tutaj dostęp do właściwości jest uzyskiwany bezpośrednio, zamiast wywoływania funkcji.
Jeśli ta propozycja zostanie zaakceptowana, możliwe będzie pisanie kodu JavaScript w sposób bardziej podobny do tradycyjnych języków obiektowych, takich jak Java i C♯.
Edycja : ujednolicona propozycja pól klas jest teraz na etapie 3; aktualizacja do pakietów Babel v7.x.
Edycja (luty 2020 r.) : Funkcje klas statycznych zostały podzielone na inną propozycję. Dzięki @ GOTO0!
źródło
W aktualnych wersjach ECMAScript 6 (stan na luty 2015), wszystkie właściwości klas muszą być metodami, a nie wartościami (uwaga w ECMAScript "właściwość" jest koncepcją podobną do pola OOP, z wyjątkiem tego, że wartość pola musi być
Function
obiektem, a nie jakąkolwiek inna wartość, taka jak aNumber
lubObject
).Nadal można je określić za pomocą tradycyjnych specyfikatorów właściwości konstruktora ECMAScript:
class Agent { } Agent.CIRCLE = 1; Agent.SQUARE = 2; ...
źródło
class
składnia ES6 i tak jest tylko cukrem składniowym dla tradycyjnych funkcji konstruktorów JS i prototypów.enum
).class
składnia ma również pewne niuanse różnic. Na przykład metoda zadeklarowana za pomocąClass.prototype.method = function () {};
jest wyliczalna (widoczna w pętlach for-in), podczas gdyclass
metody nie są wyliczalne.Aby w pełni wykorzystać zmienną statyczną, zastosowałem to podejście. Mówiąc dokładniej, możemy go użyć do użycia zmiennej prywatnej lub posiadania tylko publicznego pobierającego, lub mając jednocześnie pobierający lub ustawiający. W ostatnim przypadku jest to to samo, co jedno z opisanych powyżej rozwiązań.
var Url = (() => { let _staticMember = []; return class { static getQueries(hash = document.location.hash) { return hash; } static get staticMember(){ return _staticMember; } }; })(); Usages: console.log(Url.staticMember); // []; Url.staticMember.push('it works'); console.log(Url.staticMember); // ['it works'];
Mogłem stworzyć inną rozszerzającą klasę Url i zadziałało.
Użyłem babel do konwersji mojego kodu ES6 do ES5
źródło
class Url { static getQueries… }; Url.staticMember = [];
byłoby dużo prostsze?===
porównania dają wynikfalse
, przy okazjiOdpowiedź @kangax nie naśladuje całego statycznego zachowania tradycyjnego języka OOP, ponieważ nie możesz uzyskać dostępu do statycznej właściwości przez jej instancję, taką jak
const agent = new Agent; agent.CIRCLE; // Undefined
Jeśli chcesz uzyskać dostęp do właściwości statycznej, tak jak OOP, oto moje rozwiązanie:
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance } } NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
Kod testowy w następujący sposób.
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { console.log('this.constructor.name:', this.constructor.name); // late binding return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; } } // Static property can be accessed by class NewApp.MULTIPLE_VERSIONS_SUPPORTED = true; const newApp = new NewApp; // Static property can be accessed by it's instances console.log('newApp.MULTIPLE_VERSIONS_SUPPORTED:', newApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Inheritance class StandardApp extends NewApp {} // Static property can be inherited console.log('StandardApp.MULTIPLE_VERSIONS_SUPPORTED:', StandardApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Static property can be overwritten StandardApp.MULTIPLE_VERSIONS_SUPPORTED = false; const std = new StandardApp; console.log('std.MULTIPLE_VERSIONS_SUPPORTED:', std.MULTIPLE_VERSIONS_SUPPORTED); // false
źródło
static
pola przez instancję byłoby raczej rzadkie, prawda? W niektórych językach, takich jak Java, IDE faktycznie wyświetla ostrzeżenie / wskazówkę, jeśli robisz coś takiego.