Kokia yra pageidaujama sintaksė apibrėžiant „Enums“ javascript'e?

Kokia yra pageidaujama sintaksė apibrėžiant „Enums“ javascript'e? Kažkas panašaus:

 my.namespace.ColorEnum = { RED : 0, GREEN : 1, BLUE : 2 } // later on if(currentColor == my.namespace.ColorEnum.RED) { // whatever } 

Ar yra pirmenybė?

1818 m
13 нояб. nustatė Davidas Citronas lapkričio 13 d 2008-11-13 22:09 '08 10:09 val. 2008-11-13 22:09
@ 46 atsakymai
  • 1
  • 2

Nuo 1.8.5 punkto objektą galima užsandarinti ir užšaldyti, todėl pirmiau nurodoma:

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

arba

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

ir voila! JS sąrašai.

Tačiau tai netrukdo priskirti kintamajam nepageidaujamą vertę, kuri dažnai yra pagrindinis sąrašų tikslas:

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

Vienas iš būdų užtikrinti aukštesnį tipo saugos lygį (naudojant sąrašus arba kitaip) yra naudoti tokį įrankį kaip „ TypeScript“ arba „ Flow“ .

Šaltinis

Citatos nereikalingos, tačiau išsaugojau nuoseklumą.

665
18 февр. Atsakymas pateikiamas Artur Czajka 18 vasario mėn. 2011-02-18 14:03 '11 at 14:03 2011-02-18 14:03

Tai nėra atsakymas, bet norėčiau pasakyti, kad jis puikiai veikia, asmeniškai.

border=0

Sakydamas, kad nesvarbu, kokias vertybes (jūs naudojote 0, 1, 2), naudoju prasmingą eilutę, jei kada nors norėjote išleisti dabartinę vertę.

592
13 нояб. Atsakymą pateikė Gareth , lapkričio 13 d. 2008-11-13 22:13 '08 10:13 val. 2008-11-13 22:13

UPDATE . Dėkojame visiems už viską, kas man patinka, bet nemanau, kad žemiau pateiktas atsakymas yra geriausias būdas parašyti „Javascript“ įrašus. Daugiau informacijos rasite „Mano dienoraštyje“: „ Javascript“ skaičiavimai .


Pavadinimo įspėjimas jau galimas:

 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); } } 

Arba galite sukurti vertės objektus, kad galėtumėte gauti pyragą ir valgyti:

 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); } 

„Javascript“, nes tai yra dinamiška kalba, netgi galima pridėti skaičiavimo reikšmes rinkiniui vėliau:

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

Atminkite, kad skaičiavimo laukai (vertė, pavadinimas ir kodas šiame pavyzdyje) autentifikavimui nereikalingi ir yra prieinami tik patogumui. Be to, paties dydžio nuosavybės pavadinimas neturi būti koduotas, tačiau jis taip pat gali būti nustatytas dinamiškai. Tarkime, kad žinote tik naujo „enum“ vertės pavadinimą, galite jį pridėti be jokių problemų:

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

Žinoma, tai reiškia, kad kai kurių prielaidų nebegalima (pvz., Ši vertė atitinka teisingą dydžio dydį).

Atminkite, kad „Javascript“ objekte jis atrodo kaip žemėlapio ar maišos lentelė. Vardų vertės porų rinkinys. Galite juos slinkti arba kitaip juos manipuliuoti, nežinodami jų iš anksto.

pavyzdžiui:

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

Ir btw, jei jus domina vardų erdvės, galbūt norėsite pažvelgti į mano sprendimą paprastam, bet galingam vardų erdvių valdymui ir „JavaScript“: JS paketų priklausomybei

484
05 марта '10 в 1:31 2010-03-05 01:31 Atsakymą pateikė Stijn de Witt kovo 5 d. 10 d. 1:31 val. 2010-03-05 01:31

Apatinė eilutė: jūs negalite.

Jūs galite suklastoti, bet jūs negalite gauti saugumo tipo. Paprastai tai daroma sukuriant paprastą eilutės reikšmių žodyną, susietą su sveikojo skaičiaus reikšmėmis. Pavyzdžiui:

 var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...} Document.Write("Enumerant: " + DaysEnum.tuesday); 

Problema su šiuo požiūriu? Jūs galite atsitiktinai panaikinti savo skaitiklį arba atsitiktinai gauti pasikartojančias vertes. Pavyzdžiui:

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

Keisti

Kaip apie Arthur Tsayki Object.freeze? Ar tai neužkerta kelio nustatyti nuo pirmadienio iki ketvirtadienio? - Fry Quad

Absoliučiai, Object.freeze visiškai pašalins problemą, dėl kurios skundėsiu. Norėčiau visiems priminti, kad kai parašiau aukščiau, „ Object.freeze tikrai neegzistavo.

Dabar ... dabar ji atveria keletą labai įdomių galimybių.

Redaguoti 2
Čia yra labai gera biblioteka, skirta kurti sąrašus.

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

Nors tai tikriausiai netinka bet kokiam galiojančiam sąrašų naudojimui, tai užtrunka labai ilgai.

80
21 авг. atsakymą pateikė Randolpho 21 rug. 2009-08-21 23:56 '09 at 11:56 PM 2009-08-21 23:56

Čia mes visi norime:

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

Dabar galite sukurti savo įrašus:

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

Taigi konstantos gali būti vykdomos įprastu būdu (YesNo.YES, Color.GREEN), ir jos gauna nuoseklią int reikšmę (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

Taip pat galite pridėti metodus naudodami „Enum.prototype“:

 Enum.prototype.values = function() { return this.allValues;  }; 


Redaguoti - nedidelį patobulinimą - dabar su varargs: (deja, jis neveikia tinkamai IE: S ... privalo laikytis ankstesnės versijos)

 function Enum() { for (var i in arguments) { this[arguments[i]] = i; } } var YesNo = new Enum('NO', 'YES'); var Color = new Enum('RED', 'GREEN', 'BLUE'); 
51
13 июля '11 в 3:28 2011-07-13 03:28 atsakymą pateikė Andre'as Fi'as liepos 11 d. 11 val. 03:28 2011-07-13 03:28

Daugumoje šiuolaikinių naršyklių yra simbolių primityvus duomenų tipas, kurį galite naudoti norint sukurti sąrašą. Tai užtikrins įrašų tipų saugumą, nes kiekviena simbolių reikšmė garantuojama kaip unikali „JavaScript“, ty Symbol() != Symbol() . Pavyzdžiui:

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

Norėdami supaprastinti derinimą, galite pridėti aprašymus į išvardytas reikšmes:

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

Plunkerio demonstracija

GitHub“ galite rasti apvalkalą, kuris supaprastina kodą, reikalingą inicijuoti „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 
45
05 мая '15 в 19:32 2015-05-05 19:32 atsakymas pateikiamas Vitalii Fedorenko 05 gegužės 15 d. 19:32 2015-05-05 19:32

Su tuo žaidžiau, nes man patinka mano įrašai. =)

Object.defineProperty Manau, kad atėjau šiek tiek perspektyvaus sprendimo.

Čia yra jsfiddle: http://jsfiddle.net/ZV4A6/

Naudojant šį metodą, jūs (teoriškai) turite sugebėti skambinti ir apibrėžti bet kurio objekto skaičiavimo reikšmes, nedarant įtakos kitiems šio objekto atributams.

 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 }); 

Dėl writable:false atributo, tai turėtų būti saugi.

Taigi turėtumėte sugebėti sukurti pasirinktinį objektą ir paskambinti Enum() . Priskirtų reikšmių reikšmės prasideda nuo 0 ir kiekvieno elemento prieaugis.

 var EnumColors={}; EnumColors.Enum('RED','BLUE','GREEN','YELLOW'); EnumColors.RED; // == 0 EnumColors.BLUE; // == 1 EnumColors.GREEN; // == 2 EnumColors.YELLOW; // == 3 
22
21 авг. atsakymas duodamas 21 d. 2013-08-21 13:34 '13, 13:34, 2013-08-21 13:34

Tai senas, kurį žinau, tačiau būdas, kaip jis buvo įdiegtas naudojant „TypeScript“ sąsają, yra:

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

Tai leidžia jums ieškoti ir „ MyEnum.Bar , kuris grąžina 1, ir „ MyEnum[1] , kuris grąžina „Bar“, nepriklausomai nuo skelbimo tvarkos.

18
24 июня '13 в 19:11 2013-06-24 19:11 atsakymą pateikė Robas Hardy , birželio 24 d., 13 val., 2013-11-24 19:11

Daugumos žmonių „pageidaujamoji sintaksė“ jau yra išvardyta aukščiau. Tačiau yra pagrindinė bendra problema: našumas. Nė vienas iš pirmiau pateiktų atsakymų nėra labai veiksmingas, ir visi jie padidina jūsų kodo dydį iki ribos. Tam, kad realiai veiktų, kodų skaitymas būtų paprastas ir kad būtų sumažintas precedento neturintis kodo mažinimas, tai yra teisingas būdas suskaičiuoti.

 const ENUM_COLORENUM_RED = 0, ENUM_COLORENUM_GREEN = 1, ENUM_COLORENUM_BLUE = 2, ENUMLEN_COLORENUM = 3; // later on if(currentColor == ENUM_COLORENUM_RED) { // whatever } 

Be to, ši sintaksė leidžia aiškiai ir glaustai išplėsti klases, kaip parodyta žemiau.

(Ilgis: 2450 baitų)

čia .  Uždarymo kompiliatorius gali paimti visus šiuos skaičiavimo duomenis ir įdėti juos, todėl jūsų javascript yra greitas ir labai mažas.  Atkreipkite dėmesį. 

(Ilgis: 605 baitai)

Šaltinis be šių sąrašų (ilgis: 1973 baitai (477 baitai trumpesni!)) 
Nenurodomi šie skaičiai (ilgis: 843 baitai (238 baitai daugiau ))

Kaip matote, be sąrašo šaltinio kodas yra trumpesnis dėl didesnio sumažinto kodo. Nežinau apie jus, aš tikrai žinau, kad nenoriu įtraukti galutinio produkto šaltinio kodo, todėl šis sąrašo metodas yra daug geresnis, nes tai mažesnius failų dydžius. Pridėkite tai, kad ši įtraukimo forma yra daug greičiau. Iš tiesų, tokia skaičiavimo forma yra kelias.

16
15 мая '18 в 19:53 2018-05-15 19:53 atsakė Jack Giffin'ui gegužės 18 d. 18, 19:53 2018-05-15 19:53

ES7 galite sukurti elegantišką enumą, kuris remiasi statiniais atributais:

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

kad

 if (currentColor === ColorEnum.GREEN ) {} 

Privalumas (naudojant klasę, o ne pažodinį objektą) yra turėti pagrindinę klasę „ Enum , tada visos jūsų „Enums“ išplės šią klasę.

  class ColorEnum extends Enum {} 
15
06 янв. atsakymą pateikė Abdennour TOUMI 06 sausis 2017-01-06 10:07 '17 at 10:07 2017-01-06 10:07

Tai yra sprendimas, kurį naudoju.

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

Taip pat apibrėžiate savo pervedimus taip:

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

Ir taip galite pasiekti savo įrašus:

 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 }); 

Paprastai aš naudoju paskutinius 2 metodus, kad suderintumėte Enumus nuo pranešimų objektų.

Kai kurie šio požiūrio privalumai:

  • Lengvai deklaruojami pervedimai
  • Lengva prieiga prie jūsų sąrašų.
  • Jūsų sąrašai gali būti sudėtingi.
  • „Enum“ klasė turi tam tikrą asociatyvų talpyklą, jei naudojate getByValue daug

Kai kurie trūkumai yra:

  • Jame vyksta šiek tiek nešvarios atminties valdymo, nes laikau nuorodas į „Enums“.
  • Vis dar nėra saugumo tipo
15
15 мая '12 в 12:26 2012-05-15 12:26 Atsakymą davė Chris gegužės 15 d. 12:26 2012-05-15 12:26

Naudokite „Javascript Proxies“

TL; DR: pridėkite šią klasę prie naudingumo metodų ir naudokite jį visame kode, jis imituoja Enum elgesį iš tradicinių programavimo kalbų ir iš tikrųjų suteikia klaidų, kai bandote pasiekti neegzistuojančią skaitiklį arba pridėti / atnaujinti skaitiklį. Nereikia pasikliauti Object.freeze() .

 class Enum { constructor(enumObj) { const handler = { get(target, name) { if (target[name]) { return target[name]; } throw new Error('No such enumerator: ${name}'); }, set() { throw new Error('Cannot add/update properties on an Enum instance after it is defined') } }; return new Proxy(enumObj, handler); } } 

Tada sukurkite enumijas, kurdami klasės egzempliorių:

 const roles = new Enum({ ADMIN: 'Admin', USER: 'User', }); 

Išsamus paaiškinimas:

Viena labai naudinga „Enums“ funkcija, kurią gausite iš tradicinių kalbų, yra tai, kad jie sprogsta (pateikia kompiliavimo laiko klaidą), jei bandote pasiekti nenaudojantį skaitiklį.

Be užšaldymo netikros enum struktūros, kad būtų išvengta atsitiktinio / kenksmingo papildomų verčių pridėjimo, nė vienas kitas atsakymas neturi įtakos šiai „Enums“ savybei.

Kaip tikriausiai žinote, prieiga prie neegzistuojančių elementų „JavaScript“ paprasčiausiai grąžina undefined ir nesprogsta jūsų kodo. Kadangi skaičiuotojai yra iš anksto nustatytos konstantos (ty savaitės dienos), niekada neturėtų būti atvejo, kai skaitiklis turėtų būti neapibrėžtas.

Nesupraskite manęs, kad „JavaScript“ elgesys, kai grįžta į undefined kai pasiekiate neapibrėžtas savybes, iš tikrųjų yra labai galinga kalbos funkcija, bet ne funkcija, kurios jums reikia, kai bandote modeliuoti tradicines Enum struktūras.

Čia atspindi proxy objektai. Įgaliotieji asmenys buvo standartizuoti kalba su ES6 (ES2015). Čia yra aprašymas iš MDN:

Tarpinis objektas naudojamas apibrėžti pasirinktinį elgesį pagrindinėms operacijoms (pavyzdžiui, ieškant savybių, priskyrimo, skaičiavimo, funkcijų skambučio ir tt).

Kaip ir interneto serverio proxy serveris, „JavaScript“ proxy serveriai gali perimti operacijas objektuose (naudodami spąstus, skambindami juos kabliukais, jei norite) ir leisdami atlikti įvairius patikrinimus, veiksmus ir (arba) manipuliacijas prieš jų užbaigimą (arba kai kuriais atvejais apskritai, operacijų nutraukimas, kurį mes norime daryti, jei ir kada stengiamės kreiptis į nesąrašytoją, kuris neegzistuoja).

Čia yra išgalvotas pavyzdys, kuris naudoja proxy objektą, kad imituotų Enumą. Šiame pavyzdyje skaitikliai yra standartiniai HTTP metodai (pvz., „GET“, „POST“ ir tt):

16 марта '18 в 0:09 2018-03-16 00:09 atsakė Govindui Rai kovo 18 d. 18 val. 0:09 2018-03-16 00:09

Kurti objektą pažodžiui:

 const Modes = { DRAGGING: 'drag', SCALING: 'scale', CLICKED: 'click' }; 
12
26 июля '15 в 15:03 2015-07-26 15:03 atsakymas pateikiamas liepos 26 d. 15 val. 15:03 2015-07-26 15:03

Jei naudojate „ Backbone“ , galite gauti visą funkciją turinčią skaičiavimo funkciją (pagal ID, pavadinimą, pasirinktinius narius) nemokamai naudodami 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() 
11
24 апр. Jaroslavo atsakymas, pateiktas balandžio 24 d 2012-04-24 17:04 '12 at 5:04 val. 2012-04-24 17:04

Jūsų atsakymai yra per daug sudėtingi.

 var buildSet = function(array) { var set = {}; for (var i in array) { var item = array[i]; set[item] = item; } return set; } var myEnum = buildSet(['RED','GREEN','BLUE']); // myEnum.RED == 'RED' ...etc 
8
15 мая '14 в 7:20 2014-05-15 07:20 Atsakymą Heltoras pateikia gegužės 14 d. 14 d. 7:20 val. 2014-05-15 07:20

Pakeitiau Andre 'Fi' sprendimą:

  function Enum() { var that = this; for (var i in arguments) { that[arguments[i]] = i; } this.name = function(value) { for (var key in that) { if (that[key] == value) { return key; } } }; this.exist = function(value) { return (typeof that.name(value) !== "undefined"); }; if (Object.freeze) { Object.freeze(that); } } 

Bandymas:

 var Color = new Enum('RED', 'GREEN', 'BLUE'); undefined Color.name(Color.REDs) undefined Color.name(Color.RED) "RED" Color.exist(Color.REDs) false Color.exist(Color.RED) true 
7
11 апр. David Miró atsakymas balandžio 11 d 2013-04-11 15:11 '13, 15:11, 2013-04-11 15:11

IE8 nepalaiko užšaldymo () metodo.
Šaltinis: http://kangax.github.io/compat-table/es5/ , spustelėkite „Rodyti pasenusias naršykles“? aukščiau ir patikrinkite IE8 ir nustatykite stulpelių eilių sankirtą.

Mano dabartiniame žaidimo projekte, kurį naudoju toliau, nes kai kurie klientai vis dar naudoja IE8:

 var CONST_WILD_TYPES = { REGULAR: 'REGULAR', EXPANDING: 'EXPANDING', STICKY: 'STICKY', SHIFTING: 'SHIFTING' }; 

Taip pat galėtume padaryti:

 var CONST_WILD_TYPES = { REGULAR: 'RE', EXPANDING: 'EX', STICKY: 'ST', SHIFTING: 'SH' }; 

arba netgi tai:

 var CONST_WILD_TYPES = { REGULAR: '1', EXPANDING: '2', STICKY: '3', SHIFTING: '4' }; 

Pastarasis, atrodo, yra pats efektyviausias eilutei, sumažinant bendrą dažnių juostos plotį, jei turite serverį ir klientą, kuris dalijasi šiais duomenimis.
Žinoma, dabar jūsų pareiga yra įsitikinti, kad nėra duomenų konfliktų (RE, EX ir tt. Turi būti unikalūs, taip pat 1, 2 ir tt). Atkreipkite dėmesį, kad jums reikia juos visam laikui išlaikyti, kad būtų suderintas.

Tikslas:

 var wildType = CONST_WILD_TYPES.REGULAR; 

Palyginimas:

 if (wildType === CONST_WILD_TYPES.REGULAR) { // do something here } 
6
02 июля '15 в 16:03 2015-07-02 16:03 Atsakymą pateikė Manohar Reddy Poreddy liepos 2 d. 15 d. 16:03 2015-07-02 16:03

Aš atėjau šį požiūrį, kuris yra modeliuotas po „Java“ sąrašų. Jie yra saugūs, todėl galite atlikti ir patikrinimus.