ES6 sınıflarında statik sabitler bildiriliyor mu?


311

Ben sabitleri bir uygulamak istiyorum class, çünkü bu nerede onları kodu bulmak mantıklı.

Şimdiye kadar, aşağıdaki geçici yöntemleri statik yöntemlerle uyguluyorum:

class MyClass {
    static constant1() { return 33; }
    static constant2() { return 2; }
    // ...
}

Prototiplerle uğraşma olasılığı olduğunu biliyorum, ancak birçoğu buna karşı öneride bulunuyor.

ES6 sınıflarında sabitleri uygulamanın daha iyi bir yolu var mı?


7
Şahsen ben sadece büyük VARNAMES kullanın ve kendime onlara dokunmamalarını söyle;)
twicejr

3
@twicejr Bunun aynı olmadığını düşünüyorum, statik değişkenler için o sınıftaki bir nesneyi ilk örneklemeden erişilebilir mi?
Lucas Morgan

Yanıtlar:


385

İşte yapabileceğiniz birkaç şey:

Bir verme constile ilgili modül . Kullanım durumunuza bağlı olarak şunları yapabilirsiniz:

export const constant1 = 33;

Ve bunu gerektiğinde modülden içe aktarın. Veya statik yöntem fikrinizi temel alarak bir static get erişimcisi bildirebilirsiniz :

const constant1 = 33,
      constant2 = 2;
class Example {

  static get constant1() {
    return constant1;
  }

  static get constant2() {
    return constant2;
  }
}

Bu şekilde parantez gerekmez:

const one = Example.constant1;

Babel REPL Örneği

Daha sonra, dediğin gibi, a classbir işlev için sadece sözdizimsel şeker olduğundan, yazılamaz bir özelliği şu şekilde ekleyebilirsiniz:

class Example {
}
Object.defineProperty(Example, 'constant1', {
    value: 33,
    writable : false,
    enumerable : true,
    configurable : false
});
Example.constant1; // 33
Example.constant1 = 15; // TypeError

Sadece şöyle bir şey yapabilirsek iyi olabilir:

class Example {
    static const constant1 = 33;
}

Ancak maalesef bu sınıf özellik sözdizimi yalnızca bir ES7 teklifindedir ve o zaman bile constmülke eklenmesine izin vermez .


statik özelliklerin bu gibi şeyler için bir kez hesaplandığına dair herhangi bir onay var mı, yoksa dönüş değerlerinin tekrar tekrar oluşturulmasını önlemek için IIFE'yi kullanmak ve özelliği IIFE'ye manuel olarak eklemek daha güvenli mi? Alıcının sonucu gerçekten ağırsa, 100000 girişli JSObject gibi, o zaman fakir alıcının, alıcı her çağrıldığında bunu oluşturmak zorunda kalacağından endişeleniyorum. Performance.now/date diff ile test edilmesi kolaydır, ancak farklı bir şekilde uygulanabilir, alıcıları sabit olsun veya olmasın gelişmiş kararlar yerine gerçek değerlendirme olarak uygulamak daha kolaydır.
Dmitry

3
yukarıdakiler bir sınıfa akıllıca bir sabit özellik eklerken, sabitin gerçek değeri, kapsülleme tanımlarından birini gerçekten ihlal eden "{}" sınıf tanımının "dışında" dır. Sanırım sadece sınıf "içinde" sabit bir özellik tanımlamak yeterlidir ve bu durumda olsun gerek yoktur.
NoChance

1
@NoChance İyi puan. Bu sadece açıklayıcıydı. Alıcı yönteminin gerekirse değeri tam olarak kapatamaması için hiçbir neden yoktur.
CodingIntrigue

ES7 teklifini kullanmak için sabırsızlanıyorum çünkü bana daha doğal ve OO dillerinin çoğuna eşdeğer görünüyor.
Sangimed

Sabit bir örnek değişkeni bildirmek istediğim nedir? Gibi bir şey yapabilir miyimthis.defineProperty(this, 'constant1', {...})
Francesco Boi

33
class Whatever {
    static get MyConst() { return 10; }
}

let a = Whatever.MyConst;

Benim için iş gibi görünüyor.


bu sınıf içinde normal bir yöntemle erişilebilir mi?
PirateApp

3
@PirateApp, sınıfın bir örneğinden bile olsa, herhangi bir yere statik yöntem olarak erişebilirsiniz. Bununla birlikte, this.MyConstbir Whateverörneğin içinden kullanamayacağınız statik olduğundan , her zaman şu şekilde yazmanız gerekir: Whatever.MyConst
TheDarkIn1978

23

Kullanıyorum babelve aşağıdaki sözdizimi benim için çalışıyor:

class MyClass {
    static constant1 = 33;
    static constant2 = {
       case1: 1,
       case2: 2,
    };
    // ...
}

MyClass.constant1 === 33
MyClass.constant2.case1 === 1

Lütfen ön ayara ihtiyacınız olduğunu düşünün "stage-0".
Yüklemek için:

npm install --save-dev babel-preset-stage-0

// in .babelrc
{
    "presets": ["stage-0"]
}

Güncelleme:

şu anda kullan stage-3


21
Sorun şu ki, sabit yeniden atanabilir. Op bunu istemiyor
CodingIntrigue

3
FYI, bu şimdi babelstage-2
bmaupin

3
sabit değil
Dave L.

1
@CodingIntrigue Sınıfı çağırmak bunu düzeltir mi Object.freeze()?
Antimon

1
@Antimony Bunu test etmedim ama öyle düşünürdüm. Sorun sınıfın tüm özellikleri için geçerli olacaktır. Statik olmayan da.
Kodlama Giriş

14

Gelen bu belgede belirtir:

Prototip veri özelliklerini (yöntemler dışında) sınıf özelliklerini veya örnek özelliğini tanımlamanın (kasıtlı olarak) doğrudan bildirici bir yolu yoktur.

Bu, bilerek böyle olduğu anlamına gelir.

Belki yapıcıda bir değişken tanımlayabilirsiniz?

constructor(){
    this.key = value
}

2
Evet, bu işe yarayabilir. Ayrıca, bahsetmek istiyorum, kurucu örneği oluşturulduğunda çağırır ve her örnek için this.key aynı olmayacaktır. Statik yöntem ve özellikler, bunları örnek oluşturmadan doğrudan sınıftan kullanmamıza izin verir. Statik yöntemlerin / özelliklerin iyi ve zayıf noktaları vardır.
Kirill Gusyatin

1
Sabitler değişmez olmalıdır. İnşaat sırasında nesne üzerindeki özelliklere atandığında, değiştirilebilecek özellikler elde edilir.
philraj

11

Ayrıca, Object.freezesınıf (es6) / yapıcı işlevi (es5) nesnesini değiştirilemez hale getirmek için kullanmak da mümkündür :

class MyConstants {}
MyConstants.staticValue = 3;
MyConstants.staticMethod = function() {
  return 4;
}
Object.freeze(MyConstants);
// after the freeze, any attempts of altering the MyConstants class will have no result
// (either trying to alter, add or delete a property)
MyConstants.staticValue === 3; // true
MyConstants.staticValue = 55; // will have no effect
MyConstants.staticValue === 3; // true

MyConstants.otherStaticValue = "other" // will have no effect
MyConstants.otherStaticValue === undefined // true

delete MyConstants.staticMethod // false
typeof(MyConstants.staticMethod) === "function" // true

Sınıfı değiştirmeye çalışmak size yumuşak bir hata verecektir (herhangi bir hata atmayacak, sadece bir etkisi olmayacaktır).


3
Bu yumuşak başarısızlık, diğer dillerden gelenlerimiz için oldukça korkutucu - sadece araçların hata bulmada bize çok fazla yardımcı olmadığı fikrine adapte olmak, şimdi çalışma zamanı bile yardımcı olmayacak. (Aksi takdirde çözümünüzü seviyorum.)
Tom

Object.freeze()Değişmezliği güçlendirmeyi seviyorum ve son zamanlarda çok kullanıyorum. Sadece tekrar tekrar uygulamayı unutmayın!
jeffwtribble

6

Belki de tüm sabitlerinizi donmuş bir nesneye koymalısınız?

class MyClass {

    constructor() {
        this.constants = Object.freeze({
            constant1: 33,
            constant2: 2,
        });
    }

    static get constant1() {
        return this.constants.constant1;
    }

    doThisAndThat() {
        //...
        let value = this.constants.constant2;
        //...
    }
}

Statik işlev 'this' değişkenini kullanamaz.
PokerFace

4

Gibi https://stackoverflow.com/users/2784136/rodrigo-botti dedi, ben aradığınız düşünüyorum Object.freeze(). İşte değişmez statiklere sahip bir sınıf örneği:

class User {
  constructor(username, age) {
    if (age < User.minimumAge) {
      throw new Error('You are too young to be here!');
    }
    this.username = username;
    this.age = age;
    this.state = 'active';
  }
}

User.minimumAge = 16;
User.validStates = ['active', 'inactive', 'archived'];

deepFreeze(User);

function deepFreeze(value) {
  if (typeof value === 'object' && value !== null) {
    Object.freeze(value);
    Object.getOwnPropertyNames(value).forEach(property => {
      deepFreeze(value[property]);
    });
  }
  return value;
}

1

İşte yapmanın bir yolu daha

/*
one more way of declaring constants in a class,
Note - the constants have to be declared after the class is defined
*/
class Auto{
   //other methods
}
Auto.CONSTANT1 = "const1";
Auto.CONSTANT2 = "const2";

console.log(Auto.CONSTANT1)
console.log(Auto.CONSTANT2);

Not - Sipariş önemlidir, yukarıdaki sabitlere sahip olamazsınız

Kullanım console.log (Auto.CONSTANT1);


5
Yine de değişmez değiller
John Harding

1

ES6 sınıflarının tuhaf bir özelliğini kullanarak bir sınıftaki statik sabitleri tanımlamanın bir yolunu oluşturabilirsiniz. Statik alt sınıfları tarafından miras alındığından, aşağıdakileri yapabilirsiniz:

const withConsts = (map, BaseClass = Object) => {
  class ConstClass extends BaseClass { }
  Object.keys(map).forEach(key => {
    Object.defineProperty(ConstClass, key, {
      value: map[key],
      writable : false,
      enumerable : true,
      configurable : false
    });
  });
  return ConstClass;
};

class MyClass extends withConsts({ MY_CONST: 'this is defined' }) {
  foo() {
    console.log(MyClass.MY_CONST);
  }
}

1

Sınıfı dondurarak "sabitleri" salt okunur (değişmez) yapabilirsiniz. Örneğin

class Foo {
    static BAR = "bat"; //public static read-only
}

Object.freeze(Foo); 

/*
Uncaught TypeError: Cannot assign to read only property 'BAR' of function 'class Foo {
    static BAR = "bat"; //public static read-only
}'
*/
Foo.BAR = "wut";

0

Eğer işlev ve sınıf sözdizimi arasında rahat karıştırma ve eşleştirme yapıyorsanız, dersten sonra sabitleri bildirebilirsiniz (sabitler 'kaldırılır'). Visual Studio Code, karışık sözdizimini otomatik olarak biçimlendirmek için uğraşacağını unutmayın (çalışmasına rağmen).

class MyClass {
    // ...

}
MyClass.prototype.consts = { 
    constant1:  33,
    constant2: 32
};
mc = new MyClass();
console.log(mc.consts.constant2);    


0

Bunu ben yaptım.

class Circle
{
    constuctor(radius)
    {
        this.radius = radius;
    }
    static get PI()
    {
        return 3.14159;
    }
}

PI değeri bir işlevden döndürülen bir değer olduğundan değiştirilmeye karşı korunur. Buna Circle.PI aracılığıyla erişebilirsiniz. Herhangi bir atama girişimi, [] aracılığıyla bir dize karakterine atama girişimine benzer bir şekilde yere bırakılır.


0

Bunu şu şekilde tanımlayabilirsiniz:

class Foo {
  static MyConst = 200;

  myFunc() {
    const doubleConst = Foo.MyConst * 2;
  }
}

0

import * asSözdizimi kullanabilirsiniz . Sınıf olmasa da gerçek constdeğişkenlerdir.

Constants.js

export const factor = 3;
export const pi = 3.141592;

index.js

import * as Constants from 'Constants.js'
console.log( Constants.factor );
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.