Pertanyaan Apa sintaks yang disukai untuk mendefinisikan enum di JavaScript?


Apa sintaks yang disukai untuk mendefinisikan enum di JavaScript? Sesuatu seperti:

my.namespace.ColorEnum = {
    RED : 0,
    GREEN : 1,
    BLUE : 2
}

// later on

if(currentColor == my.namespace.ColorEnum.RED) {
   // whatever
}

Atau apakah ada idiom yang lebih disukai?


1675
2017-11-13 19:09


asal


Jawaban:


Karena 1.8.5 dimungkinkan untuk menutup dan membekukan objek, jadi tentukan di atas sebagai:

var DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})

atau

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}
Object.freeze(DaysEnum)

dan voila! JS enum.

Namun, ini tidak mencegah Anda menugaskan nilai yang tidak diinginkan ke variabel, yang sering menjadi tujuan utama enum:

let day = DaysEnum.tuesday
day = 298832342 // goes through without any errors

Salah satu cara untuk memastikan tingkat keamanan tipe yang lebih kuat (dengan enum atau lainnya) adalah dengan menggunakan alat seperti TypeScript atau Mengalir.

Sumber

Kutipan tidak diperlukan tetapi saya menyimpannya untuk konsistensi.


539
2018-02-18 11:03



Ini tidak banyak jawaban, tapi saya akan mengatakan itu bekerja dengan baik, secara pribadi

Setelah mengatakan itu, karena tidak peduli apa nilai-nilai (Anda telah menggunakan 0, 1, 2), saya akan menggunakan string yang berarti jika Anda ingin menghasilkan nilai saat ini.


583
2017-11-13 19:13



MEMPERBARUI: Terima kasih atas semua upvote semua orang, tapi saya tidak berpikir jawaban saya di bawah ini adalah cara terbaik untuk menulis enum di Javascript lagi. Lihat posting blog saya untuk detail lebih lanjut: Enum dalam Javascript.


Memberi tahu nama sudah dimungkinkan:

if (currentColor == my.namespace.ColorEnum.RED) {
   // alert name of currentColor (RED: 0)
   var col = my.namespace.ColorEnum;
   for (var name in col) {
     if (col[name] == col.RED)
       alert(name);
   }
}

Atau, Anda bisa membuat objek nilai, sehingga Anda dapat memiliki kue dan memakannya juga:

var SIZE = {
  SMALL : {value: 0, name: "Small", code: "S"}, 
  MEDIUM: {value: 1, name: "Medium", code: "M"}, 
  LARGE : {value: 2, name: "Large", code: "L"}
};

var currentSize = SIZE.MEDIUM;
if (currentSize == SIZE.MEDIUM) {
  // this alerts: "1: Medium"
  alert(currentSize.value + ": " + currentSize.name);
}

Dalam Javascript, karena ini adalah bahasa yang dinamis, bahkan dimungkinkan untuk menambahkan nilai enum ke set nanti:

// Add EXTRALARGE size
SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"};

Ingat, bidang enum (nilai, nama dan kode dalam contoh ini) tidak diperlukan untuk pemeriksaan identitas dan hanya ada untuk kenyamanan. Juga nama ukuran properti itu sendiri tidak perlu hardcoded, tetapi juga dapat diatur secara dinamis. Jadi seandainya Anda hanya tahu nama untuk nilai enum baru Anda, Anda masih dapat menambahkannya tanpa masalah:

// Add 'Extra Large' size, only knowing it's name
var name = "Extra Large";
SIZE[name] = {value: -1, name: name, code: "?"};

Tentu saja ini berarti bahwa beberapa asumsi tidak bisa lagi dibuat (nilai tersebut mewakili urutan yang benar untuk ukuran misalnya).

Ingat, dalam Javascript suatu objek sama seperti peta atau hashtable. Seperangkat pasangan nama-nilai. Anda dapat mengulangnya atau memanipulasinya tanpa mengetahui banyak hal sebelumnya.

MISALNYA:

for (var sz in SIZE) {
  // sz will be the names of the objects in SIZE, so
  // 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'
  var size = SIZE[sz]; // Get the object mapped to the name in sz
  for (var prop in size) {
    // Get all the properties of the size object, iterates over
    // 'value', 'name' and 'code'. You can inspect everything this way.        
  }
} 

Dan btw, jika Anda tertarik dalam ruang nama, Anda mungkin ingin melihat solusi saya untuk namespace sederhana dan kuat dan manajemen ketergantungan untuk javascript: Paket JS


477
2018-03-04 22:31



Intinya: Anda tidak bisa.

Anda bisa memalsukannya, tetapi Anda tidak akan mendapatkan jenis keamanan. Biasanya ini dilakukan dengan membuat kamus sederhana nilai string yang dipetakan ke nilai integer. Sebagai contoh:

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}

Document.Write("Enumerant: " + DaysEnum.tuesday);

Masalah dengan pendekatan ini? Anda dapat secara tidak sengaja mendefinisikan kembali enumerant Anda, atau secara tidak sengaja memiliki nilai enumeransi duplikat. Sebagai contoh:

DaysEnum.monday = 4; // whoops, monday is now thursday, too

Edit 

Bagaimana dengan Artur Czajka's Object.freeze? Bukankah itu akan mencegah Anda dari pengaturan hari Senin hingga Kamis? - Fry Quad

Benar, Object.freeze akan benar-benar memperbaiki masalah yang saya keluhkan. Saya ingin mengingatkan semua orang bahwa ketika saya menulis di atas, Object.freeze tidak benar-benar ada.

Sekarang .... sekarang membuka beberapa sangat kemungkinan menarik.

Edit 2
Berikut ini pustaka yang sangat bagus untuk membuat enum.

http://www.2ality.com/2011/10/enums.html

Meskipun mungkin tidak cocok untuk setiap penggunaan enum yang valid, itu berjalan sangat jauh.


79
2017-08-21 20:56



Inilah yang kita semua inginkan:

function Enum(constantsList) {
    for (var i in constantsList) {
        this[constantsList[i]] = i;
    }
}

Sekarang Anda dapat membuat enum Anda:

var YesNo = new Enum(['NO', 'YES']);
var Color = new Enum(['RED', 'GREEN', 'BLUE']);

Dengan melakukan ini, konstanta dapat diintegrasikan dengan cara biasa (YesNo.YES, Color.GREEN) dan mereka mendapatkan nilai int secara berurutan (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

Anda juga dapat menambahkan metode, dengan menggunakan Enum.prototype:

Enum.prototype.values = function() {
    return this.allValues;
    /* for the above to work, you'd need to do
            this.allValues = constantsList at the constructor */
};


Edit - perbaikan kecil - sekarang dengan varargs: (sayangnya itu tidak berfungsi dengan baik pada IE: S ... harus tetap dengan versi sebelumnya kemudian)

function Enum() {
    for (var i in arguments) {
        this[arguments[i]] = i;
    }
}

var YesNo = new Enum('NO', 'YES');
var Color = new Enum('RED', 'GREEN', 'BLUE');

46
2017-07-13 00:28



Di sebagian besar peramban modern, ada a simbol tipe data primitif yang dapat digunakan untuk membuat enumerasi. Ini akan memastikan keamanan jenis enum karena setiap nilai simbol dijamin oleh JavaScript menjadi unik, yaitu. Symbol() != Symbol(). Sebagai contoh:

const COLOR = Object.freeze({RED: Symbol(), BLUE: Symbol()});

Untuk menyederhanakan proses debug, Anda dapat menambahkan deskripsi ke nilai enum:

const COLOR = Object.freeze({RED: Symbol("RED"), BLUE: Symbol("BLUE")});

Demo plunker

Di GitHub Anda dapat menemukan pembungkus yang menyederhanakan kode yang diperlukan untuk menginisialisasi enum:

const color = new Enum("RED", "BLUE")

color.RED.toString() // Symbol(RED)
color.getName(color.RED) // RED
color.size // 2
color.values() // Symbol(RED), Symbol(BLUE)
color.toString() // RED,BLUE

41
2018-05-05 16:32



Saya telah bermain-main dengan ini, karena saya suka enum saya. =)

Menggunakan Object.defineProperty Saya pikir saya datang dengan solusi yang agak layak.

Berikut ini jsfiddle: http://jsfiddle.net/ZV4A6/

Dengan menggunakan metode ini .. Anda harus (secara teori) dapat memanggil dan menentukan nilai enum untuk objek apa pun, tanpa mempengaruhi atribut lain dari objek tersebut.

Object.defineProperty(Object.prototype,'Enum', {
    value: function() {
        for(i in arguments) {
            Object.defineProperty(this,arguments[i], {
                value:parseInt(i),
                writable:false,
                enumerable:true,
                configurable:true
            });
        }
        return this;
    },
    writable:false,
    enumerable:false,
    configurable:false
}); 

Karena atributnya writable:false ini harus membuatnya aman.

Jadi Anda harus dapat membuat objek khusus, lalu hubungi Enum() di atasnya. Nilai yang ditetapkan mulai dari 0 dan kenaikan per item.

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3

23
2017-08-21 10:34



Ini adalah yang lama saya tahu, tetapi cara itu telah dilaksanakan melalui antarmuka TypeScript adalah:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["Foo"] = 0] = "Foo";
    MyEnum[MyEnum["FooBar"] = 2] = "FooBar";
    MyEnum[MyEnum["Bar"] = 1] = "Bar";
})(MyEnum|| (MyEnum= {}));

Ini memungkinkan Anda untuk mencari keduanya MyEnum.Bar yang mengembalikan 1, dan MyEnum[1] yang mengembalikan "Bar" terlepas dari urutan deklarasi.


17
2018-06-24 16:11



Ini adalah solusi yang saya gunakan.

function Enum() {
    this._enums = [];
    this._lookups = {};
}

Enum.prototype.getEnums = function() {
    return _enums;
}

Enum.prototype.forEach = function(callback){
    var length = this._enums.length;
    for (var i = 0; i < length; ++i){
        callback(this._enums[i]);
    }
}

Enum.prototype.addEnum = function(e) {
    this._enums.push(e);
}

Enum.prototype.getByName = function(name) {
    return this[name];
}

Enum.prototype.getByValue = function(field, value) {
    var lookup = this._lookups[field];
    if(lookup) {
        return lookup[value];
    } else {
        this._lookups[field] = ( lookup = {});
        var k = this._enums.length - 1;
        for(; k >= 0; --k) {
            var m = this._enums[k];
            var j = m[field];
            lookup[j] = m;
            if(j == value) {
                return m;
            }
        }
    }
    return null;
}

function defineEnum(definition) {
    var k;
    var e = new Enum();
    for(k in definition) {
        var j = definition[k];
        e[k] = j;
        e.addEnum(j)
    }
    return e;
}

Dan Anda mendefinisikan enum Anda seperti ini:

var COLORS = defineEnum({
    RED : {
        value : 1,
        string : 'red'
    },
    GREEN : {
        value : 2,
        string : 'green'
    },
    BLUE : {
        value : 3,
        string : 'blue'
    }
});

Dan ini adalah cara Anda mengakses enum Anda:

COLORS.BLUE.string
COLORS.BLUE.value
COLORS.getByName('BLUE').string
COLORS.getByValue('value', 1).string

COLORS.forEach(function(e){
    // do what you want with e
});

Saya biasanya menggunakan 2 metode terakhir untuk memetakan enum dari objek pesan.

Beberapa keuntungan dari pendekatan ini:

  • Mudah untuk menyatakan enum
  • Mudah mengakses enum Anda
  • Enum Anda bisa menjadi tipe kompleks
  • Kelas Enum memiliki beberapa cache asosiatif jika Anda menggunakan getByValue banyak

Beberapa kerugian:

  • Beberapa manajemen memori yang berantakan terjadi di sana, karena saya menyimpan referensi ke enum
  • Masih tidak aman

15
2018-05-15 09:26



Jika Anda menggunakan Tulang punggung, Anda bisa mendapatkan fungsi enum lengkap (temukan dengan id, nama, anggota kustom) secara gratis menggunakan Backbone.Collection.

// enum instance members, optional
var Color = Backbone.Model.extend({
    print : function() {
        console.log("I am " + this.get("name"))
    }
});

// enum creation
var Colors = new Backbone.Collection([
    { id : 1, name : "Red", rgb : 0xFF0000},
    { id : 2, name : "Green" , rgb : 0x00FF00},
    { id : 3, name : "Blue" , rgb : 0x0000FF}
], {
    model : Color
});

// Expose members through public fields.
Colors.each(function(color) {
    Colors[color.get("name")] = color;
});

// using
Colors.Red.print()

12
2018-04-24 14:04



Di ES7 , Anda dapat melakukan ENUM yang elegan dengan mengandalkan atribut statis:

class ColorEnum  {
    static RED = 0 ;
    static GREEN = 1;
    static BLUE = 2;
}

kemudian

if (currentColor === ColorEnum.GREEN ) {/*-- coding --*/}

Keuntungan (menggunakan kelas bukan objek literal) adalah memiliki kelas induk Enummaka semua Enum Anda akan meluas kelas itu.

 class ColorEnum  extends Enum {/*....*/}

11
2018-01-06 07:07