ES6クラスで静的定数を宣言していますか?


311

定数をに実装したいのclassは、コード内で定数を配置することが意味があるためです。

これまでのところ、私は静的メソッドで次の回避策を実装しています。

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

私はプロトタイプをいじる可能性があることを知っていますが、多くの人はこれを推奨しません。

ES6クラスに定数を実装するより良い方法はありますか?


7
個人的に私は大文字のVARNAMESを使用し、それらに触れないように自分自身に言います;)
Twicejr

3
@twicejr私はこれは同じではないと思います、静的変数は最初にそのクラスのオブジェクトをインスタンス化せずにアクセスできるからですか?
Lucas Morgan

回答:


385

次のことを行うことができます。

モジュールconstからをエクスポートします。ユースケースに応じて、次のことができます。

export const constant1 = 33;

そして、必要に応じてモジュールからインポートします。または、静的メソッドのアイデアに基づいて、static getアクセサーを宣言できます

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

  static get constant1() {
    return constant1;
  }

  static get constant2() {
    return constant2;
  }
}

そうすれば、括弧は不要になります。

const one = Example.constant1;

Babel REPLの例

次に、あなたが言うように、a classは関数の単なる構文糖なので、次のように書き込み不可のプロパティを追加するだけです。

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

次のようなことができればいいかもしれません。

class Example {
    static const constant1 = 33;
}

しかし、残念ながら、このクラスプロパティの構文はES7の提案にのみあり、それでもconstプロパティに追加することはできません。


このような場合に静的プロパティが1回計算されることの確認はありますか、それとも、IIFEを使用し、IIFEにプロパティを手動で追加して、戻り値が繰り返し作成されないようにする方が安全ですか。ゲッターの結果が100000エントリのJSObjectのように非常に重い場合、貧しいゲッターはゲッターが呼び出されるたびにそれを構築する必要があるのではないかと心配しています。performance.now/date diffでテストするのは簡単ですが、実装方法が異なる可能性があり、定数かどうかの高度な決定ではなく、文字どおりの評価としてゲッターを実装する方が確かに簡単です。
ドミトリー

3
上記はクラスに定数プロパティを巧妙に追加していますが、定数の実際の値はクラス定義「{}」の「外」にあり、カプセル化の定義の1つに実際に違反しています。クラスの「内部」で定数プロパティを定義するだけで十分だと思います。この場合、取得する必要はありません。
NoChance 2017年

1
@NoChance良い点。それは単なる例示でした。必要に応じて、getterメソッドが値を完全にカプセル化できなかった理由はありません。
CodingIntrigue 2017年

ES7の提案を使用することを楽しみにしています。ES7の提案は、より自然で、ほとんどのオブジェクト指向言語に相当するように思えるからです。
Sangimed

定数とインスタンス変数を宣言したいのは何ですか?私は次のようなことをすることができますthis.defineProperty(this, 'constant1', {...})
Francesco Boi

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

let a = Whatever.MyConst;

私のために働くようです。


これは通常のメソッドでクラス内でアクセスできますか?
PirateApp 2019

3
@PirateAppクラスのインスタンス内からでも、静的メソッドとしてどこにでもアクセスできます。しかし、あなたが使用することはできませんそれの静的ので、this.MyConst内側からWhatever:インスタンス、あなたは常にこのようにそれを記述する必要があります Whatever.MyConst
TheDarkIn1978

23

私が使用babelしていて、次の構文が私のために働いています:

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

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

プリセットが必要だと考えてください"stage-0"
それをインストールするには:

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

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

更新:

現在使用しています stage-3


21
問題は、定数が再割り当て可能であることです。Opはそれを望まない
CodingIntrigue

3
stage-2
参考

3
これらは定数ではありません
Dave L.

1
@CodingIntrigue Object.freeze()クラスを呼び出すとそれが修正されますか?
アンチモン2017

1
@Antimony私はテストしていませんが、そうだと思います。問題は、クラスのすべてのプロパティに適用されることです。非静的。
CodingIntrigue 2017

14

、この文書は述べて:

(意図的に)プロトタイプデータプロパティ(メソッド以外)のクラスプロパティ、またはインスタンスプロパティを定義する直接の宣言的な方法はありません。

これは意図的にこのようになっていることを意味します。

多分あなたはコンストラクタで変数を定義できますか?

constructor(){
    this.key = value
}

2
はい、これでうまくいきます。また、私が言及したいのは、インスタンスが作成されたときにコンストラクターが呼び出され、インスタンスごとにthis.keyが同じにならないことです。静的メソッドとプロパティを使用すると、インスタンスを作成せずに、クラスから直接使用できます。静的メソッド/プロパティには長所と短所があります。
Kirill Gusyatin 2017

1
定数は不変でなければなりません。構築中にオブジェクトのプロパティに割り当てると、変更可能なプロパティが生成されます。
philraj

11

Object.freezeクラス(es6)/コンストラクター関数(es5)オブジェクトを使用して不変にすることもできます:

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

クラスを変更しようとすると、ソフトフェイルが発生します(エラーはスローされず、効果はありません)。


3
このソフトフェイルは、他の言語を使用している私たちにとってはかなり恐ろしいです。ツールはエラーの発見にあまり役に立たないという考えに適応するだけで、今ではランタイムも役に立たないでしょう。(そうでなければ私はあなたの解決策が好きです。)
トム

私はObject.freeze()不変性を強制するのが大好きで、最近それを頻繁に使用しています。再帰的に適用することを忘れないでください!
jeffwtribble 2017年

6

多分ちょうどあなたのすべての定数を凍結したオブジェクトに入れますか?

class MyClass {

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

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

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

静的関数は変数 'this'を使用できません。
PokerFace

4

同様https://stackoverflow.com/users/2784136/rodrigo-bottiが言った、私はあなたが探していると思いますObject.freeze()。以下は、不変の静的クラスを持つクラスの例です。

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

これがあなたができるもう一つの方法です

/*
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);

注-順序は重要です。上記の定数は使用できません

使用法console.log(Auto.CONSTANT1);


5
それらは不変ではありません
ジョン・ハーディング

1

ES6クラスの奇妙な機能を使用して、クラスに静的定数を定義する方法を作成できます。staticはサブクラスによって継承されるため、次のことができます。

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

クラスをフリーズすることで、「定数」を読み取り専用(不変)にすることができます。例えば

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

関数とクラスの構文の混合とマッチングに慣れている場合は、クラスの後に定数を宣言できます(定数は「リフト」されます)。Visual Studio Codeは混合構文の自動フォーマットに苦労することに注意してください(機能しますが)。

class MyClass {
    // ...

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


0

これは私がしました。

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

PIの値は、関数から返される値であるため、変更されないように保護されています。Circle.PIからアクセスできます。これに割り当てようとする試みは、[]を介して文字列文字に割り当てようとするのと同様の方法で床にドロップされます。


0

次のように定義できます。

class Foo {
  static MyConst = 200;

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

0

import * as構文を使用できます。クラスではありませんが、実際のconst変数です。

Constants.js

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

index.js

import * as Constants from 'Constants.js'
console.log( Constants.factor );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.