Bir ES6 sınıfında nasıl "genel statik alan" oluşturabilirim?


86

Bir Javascript sınıfı yapıyorum ve Java'da olduğu gibi genel bir statik alana sahip olmak istiyorum. Bu ilgili koddur:

export default class Agent {
    CIRCLE: 1,
    SQUARE: 2,
    ...

Aldığım hata bu:

line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.

ES6 modülleri buna izin vermiyor gibi görünüyor. İstenen davranışı elde etmenin bir yolu var mı yoksa bir alıcı yazmam gerekiyor mu?


Hangi ECMAScript 6 motor uygulamasını kullanıyorsunuz?
Dai

Yanıtlar:


136

Erişimci ve "statik" anahtar kelime kullanarak "genel statik alan" oluşturursunuz:

class Agent {
    static get CIRCLE() {
      return 1;
    }
    static get SQUARE() {
      return 2;
    }
}

Agent.CIRCLE; // 1

Bir spesifikasyona bakarsak, 14.5 - Sınıf Tanımları - şüpheli bir şekilde alakalı bir şey görürsünüz :)

ClassElement [Verim]:
  MethodDefinition [? Verim]
  statik [? Verim] MethodDefinition;

Yani oradan 14.5.14 - Runtime Semantics: ClassDefinitionEvaluation - gerçekten göründüğü şeyi gerçekten yapıp yapmadığını kontrol etmek için takip edebilirsiniz . Özellikle, 20. adım:

  1. Her ClassElement m için yöntemlerden sırayla
    1. Eğer m isStatic yanlıştır sonra,
      1. M için PropertyDefinitionEvaluation'u proto ve false bağımsız değişkenleriyle gerçekleştirmenin sonucu olsun.
    2. Başka,
      1. Durum, m için F ve false bağımsız değişkenleriyle PropertyDefinitionEvaluation gerçekleştirmenin sonucu olsun.
    3. Durum ani bir tamamlanma ise, o zaman
      1. Çalışan yürütme bağlamının LexicalEnvironment'ı lex olarak ayarlayın.
      2. Dönüş durumu.

İsStatic daha önce tanımlanan 14.5.9

ClassElement: statik MethodDefinition True döndür
.

Bu nedenle PropertyMethodDefinition, argüman olarak "F" (yapıcı, işlev nesnesi) ile çağrılır ve bu da bu nesne üzerinde bir erişimci yöntemi oluşturur .

Bu zaten en azından IETP'de (teknik önizleme) ve 6to5 ve Traceur derleyicilerinde çalışıyor.


Arayan başka biri için, statik erişimci özellikleri henüz Node'da desteklenmiyor. : - / kangax.github.io/compat-table/es6/…
David Hernandez

1
En azından Node.js 6.x + itibariyle bu desteklenmektedir.
NuSkooler

Flow kullanıyorsanız, unsafe.enable_getters_and_setters=true.flowconfig'inize [options](can sıkıcı olan) bir satır eklemeniz gerektiğini unutmayın .
kristina 18

Bu benim için çalışmayacak `` İşlenmemiş ret TypeError: Koleksiyonların dataHashKey özelliği ayarlanamıyor {api_1 | statik get dataHashKey () {api_1 | 'koleksiyonları' döndür; api_1 | } ``
Pavan

54

Daniel Ehrenberg ve Jeff Morrison'un bu sorunu çözmeyi amaçlayan "Statik Sınıf Özellikleri" adlı bir Aşama 3 ECMAScript önerisi var . Aşama 3 "Sınıf Alanları" önerisiyle birlikte, gelecekteki kod şu şekilde görünecektir:

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'
    }
}

Yukarıdakiler şuna eşdeğerdir:

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 , sınıf alanlarını @ babel / eklenti-teklif-sınıf-özellikleri ( aşama-3 ön ayarına dahil edilmiştir) aracılığıyla aktarmayı destekler , böylece JavaScript çalışma zamanınız desteklemese bile bu özelliği kullanabilirsiniz.


@ Kangax'ın bir alıcı bildirme çözümüyle karşılaştırıldığında, bu çözüm aynı zamanda daha performanslı olabilir, çünkü burada özelliğe bir işlev çağırmak yerine doğrudan erişilir.

Bu öneri kabul edilirse, Java ve C♯ gibi geleneksel nesne yönelimli dillere daha benzer bir şekilde JavaScript kodu yazmak mümkün olacaktır.


Düzenleme : Birleştirilmiş bir sınıf alanları teklifi şu anda 3. aşamadadır; Babel v7.x paketlerine güncelleme.

Düzenleme (Şubat 2020) : Statik sınıf özellikleri farklı bir teklife ayrıldı. Teşekkürler @ GOTO0!


Sanırım ilgili teklif aslında bu ( Statik sınıf özellikleri ).
GOTO 0

29

ECMAScript 6'nın mevcut taslaklarında (Şubat 2015 itibariyle), tüm sınıf özellikleri değer değil yöntem olmalıdır (ECMAScript'te bir "özellik" kavram olarak bir OOP alanına benzer, ancak alan değeri bir Functionnesne olmalıdır , herhangi bir nesne olmamalıdır. a Numberveya Object) gibi başka bir değer .

Bunları yine de geleneksel ECMAScript yapıcı özellik belirticilerini kullanarak belirtebilirsiniz:

 class Agent {
 }
 Agent.CIRCLE = 1;
 Agent.SQUARE = 2;
 ...

11
ES6 classsözdiziminin, geleneksel JS yapıcı işlevleri ve prototipleri için yalnızca sözdizimsel bir şeker olduğunu unutmayın .
Matt Browne

Sanırım bu özellikleri, örneklerden özellik referansları aracılığıyla görünür olmaları için kurucuya değil prototipe koymak isteyeceksiniz.
Pointy

@Pointy OP'nin referans için sabitleri depolamaya çalıştığı sonucuna vardım (neredeyse bir C # /. NET gibi enum).
Dai

2
@MattBrowne Evet, ancak classsözdiziminin açık olması için belirli nüanslı farklılıklar da var. Örneğin, bir yöntem, ilan ile Class.prototype.method = function () {};olan numaralandırılabilir ise, (hazır döngüler ile görülebilir) classyöntemleri numaralandırılamaz.
Timothy Gu

4

Statik değişkenden tam olarak yararlanmak için bu yaklaşımı izledim. Daha spesifik olmak gerekirse, özel değişkeni kullanmak için veya yalnızca genel alıcıya sahip olmak veya hem alıcıya hem de ayarlayıcıya sahip olmak için kullanabiliriz. Son durumda, yukarıda açıklanan çözümlerden biriyle aynı.

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'];

Url'yi genişleten başka bir sınıf oluşturabilirdim ve işe yaradı.

ES6 kodumu ES5'e dönüştürmek için babel kullandım


1
"Tam avantaj" nedir? Daha class Url { static getQueries… }; Url.staticMember = [];basit olmaz mıydı?
Bergi

Bu ===karşılaştırmaların her ikisi de false
sonuç

"Tam Avantaj", yukarıdaki şekilde, isterseniz _staticMember'i gizli tutabileceğiniz anlamına gelir.
SM Adnan

-1

@kangax'ın cevabı, geleneksel OOP dillerinin tüm statik davranışını taklit etmez, çünkü statik özelliğe örneğin const agent = new Agent; agent.CIRCLE; // Undefined

Statik özelliğe tıpkı OOP'lar gibi erişmek istiyorsanız, işte benim çözümüm:

class NewApp {
  get MULTIPLE_VERSIONS_SUPPORTED() {
    return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance
  }
}

NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;

Kodu aşağıdaki gibi test edin.

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


1
Bir staticalana bir örnekle erişmek oldukça nadir bir durumdur, değil mi? Java gibi bazı dillerde, böyle bir şey yaparsanız IDE'ler aslında bir uyarı / ipucu verir.
Isac

@Isac Evet haklısın. Örneğe göre erişim tavsiye edilmez ve cevabım da öyle. Çözümün başka bir perspektifi. 😀
legend80s
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.