質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

6300閲覧

js - Javascript で enum を定義する方法

tiitoi

総合スコア21956

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2020/11/17 10:18

編集2020/11/17 10:43

質問内容

Javascript で、配列の添字として使用できるように、整数型の列挙子を定義したいのですがどのように書けばいいのでしょうか?
Typescript では enum 構文があるようですが、Javascript には enum 構文がないです。

以下の C++ の列挙子のようにキャスト不要で整数型として認識される列挙子を定義したいです。
よろしくおねがいします。

探しているもの

  • 定数 (あとから変更することはない)
  • 整数の値を表し、配列の添字として使用できる
  • -1 始まりの連続した整数 (-1, 0, 1, 2, ...)
  • ある名前空間以下に定数を定義したい (C++ でいうと、ある名前空間の中に定義して Zero ではなく、Number::Zero として定数を参照する)

cpp

1#include <iostream> 2#include <vector> 3 4struct Number 5{ 6 enum Type 7 { 8 Null = -1, // -1 を表す定数 9 Zero, // 0 を表す定数 10 One, // 1 を表す定数 11 Two, // 2 を表す定数 12 }; 13}; 14 15int main() 16{ 17 std::vector<std::string> array = {"a", "b", "c"}; 18 19 // 整数型として認識される列挙子 20 std::cout << array[Number::Two] << std::endl; // c 21 std::cout << std::boolalpha << (Number::Two == 2) << std::endl; // true 22}

試したこと

調べたところ、Symbol を使ったサンプルが出てきたのですが、整数型とは認識されていないためか添字としては利用できないようでした。

js

1const Number = Object.freeze({ 2 Zero: Symbol(0), 3 One: Symbol(1), 4 Two: Symbol(2) 5}); 6 7let array = ["a", "b", "c"]; 8 9console.log(array[Number.Two]); // undefined

1つ1つ変数として定義していく方法も考えましたが、グローバル名前空間に定義されてしまうことと、50個ぐらい定数があり煩雑となるため、より簡潔な方法がありましたら教えて下さい。

const Zero = 0; const One = 1; const Two = 2;

環境

  • ES 2019

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi_takatsuk

2020/11/17 10:35 編集

JavaScriptは動的型付けのため、返す値の型を縛るのは非常に難しいと思うのですが(故にジェネリクスも使えません)、 Swiftの列挙型の、rawValueメソッドのように、 列挙型のメソッドを用いて、設定した値を取り出す方法を使えば擬似的に実現できると思うのですが、 それだといかがでしょうか? (Object.definePropertyを上手く使えば、型もある程度縛れるかもしれない)
tiitoi

2020/11/17 10:43 編集

コメントありがとうございます。 配列を添字で参照する際に数値を直接書く代わりに、Number.One、Number.Two、... のような感じでコードを読みやすいように変数(定数)名で代用したいというのが目的なので、定義される変数の型は保証できなくてよいです。 > 列挙型のメソッドを用いて、設定した値を取り出す方法を使えば擬似的に実現できると思うのですが、それだといかがでしょうか? すみません。列挙型のメソッドとはどれのことでしょうか?
miyabi_takatsuk

2020/11/17 10:48

Swiftの列挙型は、定義時に、 rawValueというメソッドを持ち得まして、 列挙型定義時に、添え字に対して与えた値を取り出すことができます。 それを、JavaScriptで擬似的に実装することはできると思います。 手前味噌ではありますが、以前、JSで擬似列挙型に挑戦したことがあるので、回答させていただきます。
guest

回答2

0

ベストアンサー

こういうことでしょうか。

JavaScript

1const number = Object.freeze({ 2 Zero: 0, 3 One: 1, 4 Two: 2 5});

Javascript で、配列の添字として使用できるように、整数型の列挙子を定義したいのですがどのように書けばいいのでしょうか?

ECMAScript2019ではオブジェクトのプロパティ名に指定出来るのはString型/Symbol型だけです。
Mapをつかえば、Number型を扱う事は出来ます。

JavaScript

1const map = new Map([[-1,'Null'], [0,'Zero'], [1,'One'], [2,'Two']]);

Re: tiitoi さん

投稿2020/11/17 10:52

think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2020/11/17 11:16

ご回答ありがとうございます。想定通りの挙動になりました。 Symbol() にせずにそのまま値に数値を設定すればよかったのですね。
think49

2020/11/17 23:30

> Symbol() にせずにそのまま値に数値を設定すればよかったのですね。 Symbol() は Symbol 型の値を返しますが、 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol 数値リテラル(0,1,2,3...)は Number 型です。 > 整数型の列挙子を定義したいのですが ECMAScript2019に整数型はなく、整数値と浮動小数値をひとまとめにした Number 型がIEEE 754の範疇で定義されています。 https://jsprimer.net/basic/data-type/ --- まずはこれらの型の違いを調査することから始める事をお勧めします。 仕様書を読めるのでしたら、ES2020を読むのが良いです。 http://www.ecma-international.org/ecma-262/11.0/#sec-ecmascript-data-types-and-values http://www.ecma-international.org/ecma-262/11.0/#sec-typeof-operator 特に Object 型を別の名前(Function型,Array型,Element型...etc)と誤認する人が多いので、注意が必要です。
guest

0

Enumクラスの定義です。
(JavaScriptの抽象化は、クラスか大元のプロトタイプしか手段がありません)

javascript

1const EnumCaseStruct = (() => { 2 const key = Symbol(); 3 4 return class EnumCaseStruct { 5 constructor(val) { 6 this[key] = val; 7 } 8 // Swiftを参考に、rawValueで、値を取得できるようにしている 9 get rawValue() { 10 return this[key]; 11 } 12 }; 13})(); 14 15class Enum { 16 constructor(...cases) { 17 if (!cases.every(v => { 18 switch (typeof v) { 19 case 'object': 20 // オブジェクトの場合、各キー値にて、上のクラスのインスタンスとして定義 21 Object.keys(v).forEach(ve => { 22 Object.defineProperty(this, ve, {value: new EnumCaseStruct(v[ve])}); 23 }); 24 return true; 25 case 'string': 26 // 文字列型なら、そのまま初期化する 27 Object.defineProperty(this, v, {value: new EnumCaseStruct(v)}); 28 return true; 29 defalult: 30 // オブジェクトか、文字列型以外は受け付けないようにする 31 return false; 32 } 33 })) { 34 // オブジェクトか文字列以外は、エラーをスローする 35 throw new Error('Type error!'); 36 } 37 } 38}

使用の仕方です。

javascript

1const fruits = new Enum( 2 {apple: 25}, 3 {melon: 125} 4); 5 6const apple01 = fruits.apple; 7const apple02 = fruits.apple; 8console.log(apple01 == apple02); // true 9 10// 可変長引数のため、下記のようにも定義可能 11const fruits02 = new Enum( 12 { 13 apple: 25, 14 melon: 125 15 }, 16 'pine' 17); 18// 各列挙型は各値が一意となるため、比較時は偽となる。 19console.log(fruits.apple == fruits02.apple); // false 20// Swiftを参考に、rawValueにて、設定した値を返す 21console.log(fruits.apple.rawValue); // 25 22// 文字列をそのまま入れた場合は、rawValueはその文字列を返す 23console.log(fruits.pine.rawValue); // pine

あくまで、擬似的なため、
要件に満たないかもしれませんが、
だいぶ列挙型の使用感に近づけれはしたかと思います。

投稿2020/11/17 10:52

編集2020/11/17 10:53
miyabi_takatsuk

総合スコア9528

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2020/11/17 11:11 編集

回答いただきありがとうございます。試してみました。 const fruits = new Enum( {apple: 0}, {melon: 1} ); array = [1, 2, 3] console.log(fruits.apple == 0); // false console.log(array[fruits.apple]); // undefined 配列の添字アクセスに使いたいのですが、fruits.apple が0を表すようにはできないでしょうか?
miyabi_takatsuk

2020/11/17 11:18

すみません、その場合は、 fruits.apple.rawValue にて、0を取り出せるようにはなっています。 ただ、列挙型を一意にするために、 直接の添え字には、Symbol値を使っているため、直接、 fruits.appleから値を取り出すのは、 できないような設計になってます。 ただ、値が定数になれば良いのであれば、 Object.definePropertyを使えば可能になると思います。 上記メソッドは、 第一引数に対象のオブジェクト、 第二引数に、プロパティ名や値をいれることによって、 そのオブジェクトの定数プロパティを定義できるというものです。 MDNにて、詳しく書かれています。
tiitoi

2020/11/17 11:21 編集

なるほど。理解しました。確かに Python の enum も値を value で取り出すといった似たような仕様になっていますね。 Object.defineProperty() についても調べてみます。Javascript は始めたばかりで知らないことが多いのですが、勉強させていただきます。 ご回答ありがとうございました。
miyabi_takatsuk

2020/11/17 11:25

列挙型に囚われてしまい、少々大仰な回答になってしまったようです。すみません。 私の構文は、Pythonや、Swiftの列挙型の仕様に寄せた実装になっていると思います。 JavaScriptは、何かと自由度が高いですが、その分他の言語ではできるようなことが、逆にできなかったりするのが厄介だと思います 汗
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問