ईएस 6 के साथ जावास्क्रिप्ट में एनम


136

मैं जावास्क्रिप्ट में एक पुराने जावा प्रोजेक्ट का पुनर्निर्माण कर रहा हूं, और महसूस किया कि जेएस में एनम करने का कोई अच्छा तरीका नहीं है।

सबसे अच्छा मैं आ सकता है:

const Colors = {
    RED: Symbol("red"),
    BLUE: Symbol("blue"),
    GREEN: Symbol("green")
};
Object.freeze(Colors);

constरहता है Colorsपुन: असाइन किए जाने से, और ठंड यह कुंजी और मूल्यों परिवर्तनशील रोकता है। मैं सिंबल का उपयोग कर रहा हूं, ताकि खुद के अलावा या किसी अन्य के Colors.REDबराबर न 0हो।

इस सूत्रीकरण के साथ कोई समस्या है? क्या कोई बेहतर तरीका है?


(मुझे पता है कि यह सवाल थोड़ा दोहराने वाला है, लेकिन सभी पिछले क्यू / जैसा कि काफी पुराना है, और ईएस 6 हमें कुछ महत्वपूर्ण क्षमताएं प्रदान करता है।)


संपादित करें:

एक अन्य समाधान, जो क्रमबद्धता की समस्या से निपटता है, लेकिन मेरा मानना ​​है कि अभी भी दायरे में समस्याएँ हैं:

const enumValue = (name) => Object.freeze({toString: () => name});

const Colors = Object.freeze({
    RED: enumValue("Colors.RED"),
    BLUE: enumValue("Colors.BLUE"),
    GREEN: enumValue("Colors.GREEN")
});

मान संदर्भों के रूप में ऑब्जेक्ट संदर्भों का उपयोग करके, आपको समान टकराव-परिहार मिलता है जैसा कि प्रतीक।


2
यह es6 में एक संपूर्ण दृष्टिकोण होगा। आपको इसे फ्रीज करने की आवश्यकता नहीं है
एनआर

2
@ वायरस आप करते हैं, अगर आप इसे संशोधित नहीं करना चाहते हैं।
z

2
क्या आपने इस जवाब पर ध्यान दिया ?
बेर्गी

3
एक मुद्दा जो मैं सोच सकता हूं: इस एनम का उपयोग नहीं कर सकते JSON.stringify()। क्रमबद्ध / deserialize नहीं कर सकता Symbol
le_m

1
@EridheRed मैं बिना किसी झंझट के वर्षों से लगातार स्ट्रिंग एनम मानों का उपयोग कर रहा हूं, क्योंकि फ्लो (या टाइपस्क्रिप्ट) का उपयोग करके टकराव से बचने के बारे में कभी भी अधिक प्रकार की सुरक्षा की गारंटी देता है
एंडी

जवाबों:


131

इस सूत्रीकरण के साथ कोई समस्या है?

मुझे कोई दिखाई नहीं देता।

क्या कोई बेहतर तरीका है?

मैं दो कथनों को एक में समेटूँगा:

const Colors = Object.freeze({
    RED:   Symbol("red"),
    BLUE:  Symbol("blue"),
    GREEN: Symbol("green")
});

यदि आपको बॉयलरप्लेट पसंद नहीं है, तो बार-बार Symbolकॉल की तरह , आप निश्चित रूप से एक सहायक फ़ंक्शन भी लिख सकते हैं makeEnumजो नामों की सूची से एक ही चीज़ बनाता है।


3
यहाँ दायरे मुद्दे नहीं हैं?

2
@torazaburo का मतलब है, जब कोड को दो बार लोड किया जाता है तो यह विभिन्न प्रतीकों को उत्पन्न करेगा, जो तार के साथ एक मुद्दा नहीं होगा? हाँ, अच्छी बात है, इसे एक उत्तर दें :-)
बरगी

2
@ErictheRed नहीं है, Symbol.forकरता नहीं पार दायरे मुद्दे हैं, लेकिन यह एक साथ हमेशा की तरह टक्कर समस्या है वास्तव में एक वैश्विक नाम स्थान
बेर्गी

1
@EridheRed यह वास्तव में जब और जहाँ से (जहां से दायरे / फ्रेम / टैब / प्रक्रिया) की परवाह किए बिना सटीक एक ही प्रतीक बनाने की गारंटी देता है
बरगी

1
@jamesemanon आप विवरण प्राप्त कर सकते हैं यदि आप चाहें , लेकिन मैं इसे मुख्य रूप से केवल डिबगिंग के लिए उपयोग करूंगा। बल्कि हमेशा की तरह एक कस्टम एनम-टू-स्ट्रिंग रूपांतरण कार्य किया है (लाइनों के साथ कुछ enum => ({[Colors.RED]: "bright red", [Colors.BLUE]: "deep blue", [Colors.GREEN]: "grass green"}[enum]))।
बरगी

18

जब Symbolतक एनुम मूल्य सरल उपयोग के मामलों के लिए ठीक काम करता है, तो यह एनम को गुण देने में मदद कर सकता है। यह Objectगुण युक्त एनम मान के रूप में उपयोग करके किया जा सकता है ।

उदाहरण के लिए हम प्रत्येक Colorsनाम और हेक्स मान दे सकते हैं :

/**
 * Enum for common colors.
 * @readonly
 * @enum {{name: string, hex: string}}
 */
const Colors = Object.freeze({
  RED:   { name: "red", hex: "#f00" },
  BLUE:  { name: "blue", hex: "#00f" },
  GREEN: { name: "green", hex: "#0f0" }
});

Enum में संपत्तियों को शामिल करने से switchकथन लिखने से बचा जाता है (और संभवतया नए मामलों को स्विच स्टेटमेंट में भूल जाने पर जब कोई enum विस्तारित होता है)। उदाहरण में JSDoc enum एनोटेशन के साथ डुप्लिकेट की गई संपत्तियों और प्रकारों को दिखाया गया है ।

समानता के रूप में के साथ की उम्मीद काम करता Colors.RED === Colors.REDजा रहा है true, और Colors.RED === Colors.BLUEकिया जा रहा है false


9

जैसा कि ऊपर उल्लेख किया गया है, आप एक makeEnum()सहायक कार्य भी लिख सकते हैं :

function makeEnum(arr){
    let obj = {};
    for (let val of arr){
        obj[val] = Symbol(val);
    }
    return Object.freeze(obj);
}

इसे इस तरह उपयोग करें:

const Colors = makeEnum(["red","green","blue"]);
let startColor = Colors.red; 
console.log(startColor); // Symbol(red)

if(startColor == Colors.red){
    console.log("Do red things");
}else{
    console.log("Do non-red things");
}

2
एक-लाइनर के रूप में: const makeEnum = (...lst) => Object.freeze(Object.assign({}, ...lst.map(k => ({[k]: Symbol(k)})))); फिर इसका उपयोग करें const colors = makeEnum("Red", "Green", "Blue")
मैनुअल एबर्ट

9

यह मेरा व्यक्तिगत दृष्टिकोण है।

class ColorType {
    static get RED () {
        return "red";
    }

    static get GREEN () {
        return "green";
    }

    static get BLUE () {
        return "blue";
    }
}

// Use case.
const color = Color.create(ColorType.RED);

मैं इसका उपयोग करने की अनुशंसा नहीं करूंगा क्योंकि यह सभी संभावित मूल्यों पर पुनरावृति करने का कोई तरीका नहीं प्रदान करता है, और यह जांचने का कोई तरीका नहीं है कि क्या मान प्रत्येक के लिए मैन्युअल रूप से जाँच किए बिना एक ColorType है।
डोमिनोज

7

टाइपस्क्रिप्ट कैसे करता है, इसकी जाँच करें । मूल रूप से वे निम्नलिखित कार्य करते हैं:

const MAP = {};

MAP[MAP[1] = 'A'] = 1;
MAP[MAP[2] = 'B'] = 2;

MAP['A'] // 1
MAP[1] // A

प्रतीकों का उपयोग करें, ऑब्जेक्ट को फ्रीज करें, जो आप चाहते हैं।


मैं इसका अनुसरण नहीं कर रहा हूं क्योंकि MAP[MAP[1] = 'A'] = 1;इसके बजाय इसका उपयोग क्यों होता है MAP[1] = 'A'; MAP['A'] = 1;। मैंने हमेशा सुना है कि अभिव्यक्ति के रूप में असाइनमेंट का उपयोग करना खराब शैली है। इसके अलावा, आपको मिरर किए गए असाइनमेंट से क्या लाभ मिलता है?
एरिक द रेड

1
यहाँ एक लिंक है कि कैसे enum मानचित्रण को उनके डॉक्स में es5 में संकलित किया जाता है। typecriptlang.org/docs/handbook/enums.html#reverse-mappings मैं बस एक लाइन जैसे इसे संकलित करने के लिए आसान और अधिक संक्षिप्त हो जाएगा छवि कर सकते हैं MAP[MAP[1] = 'A'] = 1;
गढ़

हुह। तो ऐसा लगता है कि मिररिंग बस स्ट्रिंग और संख्या / प्रत्येक मूल्य के प्रतीक के बीच स्विच करना आसान बनाता है, और जांचें कि कुछ स्ट्रिंग या संख्या / प्रतीक xएक वैध एनम मान है Enum[Enum[x]] === x। यह मेरे किसी भी मूल मुद्दे को हल नहीं करता है, लेकिन उपयोगी हो सकता है और कुछ भी नहीं तोड़ सकता है।
एरिक द रेड

1
ध्यान रखें कि टाइपस्क्रिप्ट एक मजबूती की परत जोड़ता है जो TS कोड संकलित होने के बाद खो जाता है। यदि आपका पूरा ऐप टीएस में लिखा है, तो यह बहुत अच्छा है, लेकिन अगर आप चाहते हैं कि जेएस कोड मजबूत हो, तो प्रतीकों का जमी नक्शा सुरक्षित पैटर्न की तरह लगता है।
डोमिनोज़


4

आप En6 की जाँच कर सकते हैं , ES6 एनम के लिए एक बहुत अच्छी और अच्छी तरह से चित्रित पुस्तकालय।


1

शायद यह समाधान? :)

function createEnum (array) {
  return Object.freeze(array
    .reduce((obj, item) => {
      if (typeof item === 'string') {
        obj[item.toUpperCase()] = Symbol(item)
      }
      return obj
    }, {}))
}

उदाहरण:

createEnum(['red', 'green', 'blue']);

> {RED: Symbol(red), GREEN: Symbol(green), BLUE: Symbol(blue)}

एक उपयोग उदाहरण वास्तव में सराहना की जाएगी :-)
एबदर्रहमान TAHRI JOUTI

0

मैं @ टोनटर के दृष्टिकोण को पसंद करता हूं, थोड़ी सी वृद्धि के साथ और ES6 / Node.js पारिस्थितिकी तंत्र के बेहतर अंडरलाइंग को समझने के लाभ के लिए खुदाई। बाड़ के सर्वर साइड में एक पृष्ठभूमि के साथ, मैं प्लेटफ़ॉर्म की आदिमियों के चारों ओर कार्यात्मक शैली के दृष्टिकोण को प्राथमिकता देता हूं, यह कोड ब्लोट को कम करता है, नए प्रकारों की शुरुआत और वृद्धि के कारण मृत्यु की छाया के राज्य के प्रबंधन घाटी में फिसलन ढलान पठनीयता - समाधान और एल्गोरिथ्म के इरादे को और अधिक स्पष्ट करता है।

साथ समाधान TDD , ES6 , Node.js , Lodash , जेस्ट , कोलाहल , ESLint

// ./utils.js
import _ from 'lodash';

const enumOf = (...args) =>
  Object.freeze( Array.from( Object.assign(args) )
    .filter( (item) => _.isString(item))
    .map((item) => Object.freeze(Symbol.for(item))));

const sum = (a, b) => a + b;

export {enumOf, sum};
// ./utils.js

// ./kittens.js
import {enumOf} from "./utils";

const kittens = (()=> {
  const Kittens = enumOf(null, undefined, 'max', 'joe', 13, -13, 'tabby', new 
    Date(), 'tom');
  return () => Kittens;
})();

export default kittens();
// ./kittens.js 

// ./utils.test.js
import _ from 'lodash';
import kittens from './kittens';

test('enum works as expected', () => {
  kittens.forEach((kitten) => {
    // in a typed world, do your type checks...
    expect(_.isSymbol(kitten));

    // no extraction of the wrapped string here ...
    // toString is bound to the receiver's type
    expect(kitten.toString().startsWith('Symbol(')).not.toBe(false);
    expect(String(kitten).startsWith('Symbol(')).not.toBe(false);
    expect(_.isFunction(Object.valueOf(kitten))).not.toBe(false);

    const petGift = 0 === Math.random() % 2 ? kitten.description : 
      Symbol.keyFor(kitten);
    expect(petGift.startsWith('Symbol(')).not.toBe(true);
    console.log(`Unwrapped Christmas kitten pet gift '${petGift}', yeee :) 
    !!!`);
    expect(()=> {kitten.description = 'fff';}).toThrow();
  });
});
// ./utils.test.js

Array.from(Object.assign(args))बिल्कुल कुछ नहीं करता है। आप बस ...argsसीधे उपयोग कर सकते हैं।
डोमिनोज

0

यहाँ कुछ सहायक विधियों सहित मेरा दृष्टिकोण है

export default class Enum {

    constructor(name){
        this.name = name;
    }

    static get values(){
        return Object.values(this);
    }

    static forName(name){
        for(var enumValue of this.values){
            if(enumValue.name === name){
                return enumValue;
            }
        }
        throw new Error('Unknown value "' + name + '"');
    }

    toString(){
        return this.name;
    }
}

-

import Enum from './enum.js';

export default class ColumnType extends Enum {  

    constructor(name, clazz){
        super(name);        
        this.associatedClass = clazz;
    }
}

ColumnType.Integer = new ColumnType('Integer', Number);
ColumnType.Double = new ColumnType('Double', Number);
ColumnType.String = new ColumnType('String', String);

0

आप es6-enum पैकेज ( https://www.npmjs.com/package/es6-enum ) का भी उपयोग कर सकते हैं । इसका उपयोग करना बहुत आसान है। नीचे दिए गए उदाहरण देखें:

import Enum from "es6-enum";
const Colors = Enum("red", "blue", "green");
Colors.red; // Symbol(red)

10
नीचे कौन सा उदाहरण है?
अलेक्जेंडर

यदि आप एक उदाहरण बनाते हैं, तो लोग आपके उत्तर के लिए मतदान करेंगे।
आर्टेम फेडोटोव

0

यहाँ जावा में जावा गणना का मेरा कार्यान्वयन है।

मैंने यूनिट टेस्ट भी शामिल किए।

const main = () => {
  mocha.setup('bdd')
  chai.should()

  describe('Test Color [From Array]', function() {
    let Color = new Enum('RED', 'BLUE', 'GREEN')
    
    it('Test: Color.values()', () => {
      Color.values().length.should.equal(3)
    })

    it('Test: Color.RED', () => {
      chai.assert.isNotNull(Color.RED)
    })

    it('Test: Color.BLUE', () => {
      chai.assert.isNotNull(Color.BLUE)
    })

    it('Test: Color.GREEN', () => {
      chai.assert.isNotNull(Color.GREEN)
    })

    it('Test: Color.YELLOW', () => {
      chai.assert.isUndefined(Color.YELLOW)
    })
  })

  describe('Test Color [From Object]', function() {
    let Color = new Enum({
      RED   : { hex: '#F00' },
      BLUE  : { hex: '#0F0' },
      GREEN : { hex: '#00F' }
    })

    it('Test: Color.values()', () => {
      Color.values().length.should.equal(3)
    })

    it('Test: Color.RED', () => {
      let red = Color.RED
      chai.assert.isNotNull(red)
      red.getHex().should.equal('#F00')
    })

    it('Test: Color.BLUE', () => {
      let blue = Color.BLUE
      chai.assert.isNotNull(blue)
      blue.getHex().should.equal('#0F0')
    })

    it('Test: Color.GREEN', () => {
      let green = Color.GREEN
      chai.assert.isNotNull(green)
      green.getHex().should.equal('#00F')
    })

    it('Test: Color.YELLOW', () => {
      let yellow = Color.YELLOW
      chai.assert.isUndefined(yellow)
    })
  })

  mocha.run()
}

class Enum {
  constructor(values) {
    this.__values = []
    let isObject = arguments.length === 1
    let args = isObject ? Object.keys(values) : [...arguments]
    args.forEach((name, index) => {
      this.__createValue(name, isObject ? values[name] : null, index)
    })
    Object.freeze(this)
  }

  values() {
    return this.__values
  }

  /* @private */
  __createValue(name, props, index) {
    let value = new Object()
    value.__defineGetter__('name', function() {
      return Symbol(name)
    })
    value.__defineGetter__('ordinal', function() {
      return index
    })
    if (props) {
      Object.keys(props).forEach(prop => {
        value.__defineGetter__(prop, function() {
          return props[prop]
        })
        value.__proto__['get' + this.__capitalize(prop)] = function() {
          return this[prop]
        }
      })
    }
    Object.defineProperty(this, name, {
      value: Object.freeze(value),
      writable: false
    })
    this.__values.push(this[name])
  }

  /* @private */
  __capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1)
  }
}

main()
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.2.5/mocha.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.2.0/chai.js"></script>
<!--

public enum Color {
  RED("#F00"),
  BLUE("#0F0"),
  GREEN("#00F");
  
  private String hex;
  public String getHex()  { return this.hex;  }
  
  private Color(String hex) {
    this.hex = hex;
  }
}

-->
<div id="mocha"></div>


-3

आप ES6 मैप का उपयोग कर सकते हैं

const colors = new Map([
  ['RED', 'red'],
  ['BLUE', 'blue'],
  ['GREEN', 'green']
]);

console.log(colors.get('RED'));

IMHO यह इसकी जटिलता के कारण एक बुरा समाधान है (हर बार एक्सेसर विधि को कॉल करना चाहिए) और एनम प्रकृति का पुनर्संयोजन (म्यूटेटर विधि को कॉल कर सकता है और किसी भी कुंजी का मान बदल सकता है) ... इसलिए const x = Object.freeze({key: 'value'})इसके बजाय कुछ ऐसा प्राप्त करने के लिए उपयोग करें जो दिखता है
ईएस 6 में यूम की

मान प्राप्त करने के लिए आपको एक स्ट्रिंग पास करना होगा, जैसा कि आपने color.get ('RED') किया था। जो त्रुटि प्रवण है।
एड्रियन ओविदो सेप
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.