enums تعلم - ما هي الصيغة المفضلة لتعريف التعدادات في JavaScript؟





كتاب بحث (25)


لقد قمت بعمل فئة التعداد التي يمكنها جلب القيم والأسماء في O (1). يمكنه أيضًا إنشاء Object Array الذي يحتوي على كافة الأسماء والقيم.

function Enum(obj) {
    // Names must be unique, Values do not.
    // Putting same values for different Names is risky for this implementation

    this._reserved = {
        _namesObj: {},
        _objArr: [],
        _namesArr: [],
        _valuesArr: [],
        _selectOptionsHTML: ""
    };

    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            this[k] = obj[k];
            this._reserved._namesObj[obj[k]] = k;
        }
    }
}
(function () {
    this.GetName = function (val) {
        if (typeof this._reserved._namesObj[val] === "undefined")
            return null;
        return this._reserved._namesObj[val];
    };

    this.GetValue = function (name) {
        if (typeof this[name] === "undefined")
            return null;
        return this[name];
    };

    this.GetObjArr = function () {
        if (this._reserved._objArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push({
                            Name: k,
                            Value: this[k]
                        });
            }
            this._reserved._objArr = arr;
        }
        return this._reserved._objArr;
    };

    this.GetNamesArr = function () {
        if (this._reserved._namesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(k);
            }
            this._reserved._namesArr = arr;
        }
        return this._reserved._namesArr;
    };

    this.GetValuesArr = function () {
        if (this._reserved._valuesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(this[k]);
            }
            this._reserved._valuesArr = arr;
        }
        return this._reserved._valuesArr;
    };

    this.GetSelectOptionsHTML = function () {
        if (this._reserved._selectOptionsHTML.length == 0) {
            var html = "";
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        html += "<option value='" + this[k] + "'>" + k + "</option>";
            }
            this._reserved._selectOptionsHTML = html;
        }
        return this._reserved._selectOptionsHTML;
    };
}).call(Enum.prototype);

يمكنك البدء بها على النحو التالي:

var enum1 = new Enum({
    item1: 0,
    item2: 1,
    item3: 2
});

لجلب قيمة (مثل Enums في C #):

var val2 = enum1.item2;

لجلب اسم لقيمة (يمكن أن يكون غامضًا عند وضع نفس القيمة لأسماء مختلفة):

var name1 = enum1.GetName(0);  // "item1"

للحصول على مصفوفة مع كل اسم وقيمة في كائن:

var arr = enum1.GetObjArr();

سوف يولد:

[{ Name: "item1", Value: 0}, { ... }, ... ]

يمكنك أيضًا الحصول على خيارات تحديد html بسهولة:

var html = enum1.GetSelectOptionsHTML();

الذي يحمل:

"<option value='0'>item1</option>..."

ما هي الصيغة المفضلة لتعريف التعدادات في JavaScript؟ شيء مثل:

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

// later on

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

أم أن هناك تعبيرًا أكثر تفضيلاً؟




You can try this:

   var Enum = Object.freeze({
            Role: Object.freeze({ Administrator: 1, Manager: 2, Supervisor: 3 }),
            Color:Object.freeze({RED : 0, GREEN : 1, BLUE : 2 })
            });

    alert(Enum.Role.Supervisor);
    alert(Enum.Color.GREEN);
    var currentColor=0;
    if(currentColor == Enum.Color.RED) {
       alert('Its Red');
    }



خلاصة القول: لا يمكنك ذلك.

يمكنك تزييفها ، لكنك لن تحصل على أمان من النوع. عادة ما يتم ذلك عن طريق إنشاء قاموس بسيط لقيم السلسلة التي تم تعيينها إلى قيم صحيحة. فمثلا:

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

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

المشكلة مع هذا النهج؟ يمكنك إعادة تعريف العداد الخاص بك عن طريق الخطأ ، أو عن طريق الخطأ وجود قيم عددة مكررة. فمثلا:

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

تصحيح

ماذا عن كائن Art.Creeze في Artur Czajka؟ ألن يعمل هذا لمنعك من الإعداد يومًا إلى يوم الخميس؟ - فراي رباعية

على الاطلاق ، كان Object.freeze حل المشكلة التي اشتكى عنها تمامًا. أود أن أذكر الجميع أنه عندما كتبت أعلاه ، لم يكن Object.freeze موجودًا حقًا.

الآن .... الآن أنه يفتح بعض الاحتمالات المثيرة للغاية .

تحرير 2
إليك مكتبة جيدة جدًا لإنشاء التعدادات.

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

على الرغم من أنه من المحتمل أنه لا يلائم كل الاستخدامات الصالحة للتعدادات ، إلا أنه يستغرق وقتًا طويلاً جدًا.




إنشاء كائن حرفي للكائن:

const Modes = {
  DRAGGING: 'drag',
  SCALING:  'scale',
  CLICKED:  'click'
};



Simplest solution:

خلق

var Status = Object.freeze({
    "Connecting":0,
    "Ready":1,
    "Loading":2,
    "Processing": 3
});

Get Value

console.log(Status.Ready) // 1

Get Key

console.log(Object.keys(Status)[Status.Ready]) // Ready



As of writing, October 2014 - so here is a contemporary solution. Am writing the solution as a Node Module, and have included a test using Mocha and Chai, as well as underscoreJS. You can easily ignore these, and just take the Enum code if preferred.

Seen a lot of posts with overly convoluted libraries etc. The solution to getting enum support in Javascript is so simple it really isn't needed. هنا هو الرمز:

File: enums.js

_ = require('underscore');

var _Enum = function () {

   var keys = _.map(arguments, function (value) {
      return value;
   });
   var self = {
      keys: keys
   };
   for (var i = 0; i < arguments.length; i++) {
      self[keys[i]] = i;
   }
   return self;
};

var fileFormatEnum = Object.freeze(_Enum('CSV', 'TSV'));
var encodingEnum = Object.freeze(_Enum('UTF8', 'SHIFT_JIS'));

exports.fileFormatEnum = fileFormatEnum;
exports.encodingEnum = encodingEnum;

And a test to illustrate what it gives you:

file: enumsSpec.js

var chai = require("chai"),
    assert = chai.assert,
    expect = chai.expect,
    should = chai.should(),
    enums = require('./enums'),
    _ = require('underscore');


describe('enums', function () {

    describe('fileFormatEnum', function () {
        it('should return expected fileFormat enum declarations', function () {
            var fileFormatEnum = enums.fileFormatEnum;
            should.exist(fileFormatEnum);
            assert('{"keys":["CSV","TSV"],"CSV":0,"TSV":1}' === JSON.stringify(fileFormatEnum), 'Unexpected format');
            assert('["CSV","TSV"]' === JSON.stringify(fileFormatEnum.keys), 'Unexpected keys format');
        });
    });

    describe('encodingEnum', function () {
        it('should return expected encoding enum declarations', function () {
            var encodingEnum = enums.encodingEnum;
            should.exist(encodingEnum);
            assert('{"keys":["UTF8","SHIFT_JIS"],"UTF8":0,"SHIFT_JIS":1}' === JSON.stringify(encodingEnum), 'Unexpected format');
            assert('["UTF8","SHIFT_JIS"]' === JSON.stringify(encodingEnum.keys), 'Unexpected keys format');
        });
    });

});

As you can see, you get an Enum factory, you can get all the keys simply by calling enum.keys, and you can match the keys themselves to integer constants. And you can reuse the factory with different values, and export those generated Enums using Node's modular approach.

Once again, if you are just a casual user, or in the browser etc, just take the factory part of the code, potentially removing underscore library too if you don't wish to use it in your code.




إليك ما نريده جميعًا:

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

الآن يمكنك إنشاء التعدادات الخاصة بك:

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

من خلال القيام بذلك ، يمكن إدخال الثوابت بالطريقة المعتادة (YesNo.YES ، Color.GREEN) ويحصلون على قيمة int متسلسلة (NO = 0 ، YES = 1 ؛ RED = 0 ، GREEN = 1 ، BLUE = 2).

يمكنك أيضًا إضافة أساليب ، باستخدام 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 */
};


تحرير - تحسين صغير - الآن مع varargs: (لسوء الحظ أنه لا يعمل بشكل صحيح على IE: S ... يجب أن يلتزم بالإصدار السابق ثم)

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

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



في ES7 ، يمكنك إجراء ENUM أنيق بالاعتماد على السمات الثابتة:

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

ثم

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

ميزة (استخدام فئة بدلاً من كائن حرفية) هو أن يكون لديك فئة أصل Enum ثم سيتم توسيع كافة التعدادات الخاصة بك هذا الصف.

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



لا يمكنني نشر تعليق على الإجابة ، لذا أعتقد أنني سأطرق الخيط لأنه يظهر في Google.

منذ 1.8.5 من الممكن ختم وتجميد الكائن ، لذلك قم بتعريف ما سبق على النحو التالي:

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

أو

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

و فويلا! التضمين JS؛)

المصدر: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/freeze

لا حاجة إلى اقتباسات IMHO لكني احتفظ بها من أجل الاتساق.




إليك طريقتان مختلفتان لتطبيق enScript TypeScript .

أسهل طريقة هي فقط للتكرار على كائن ، مضيفا أزواج قيمة مفتاح مقلوب إلى الكائن. العيب الوحيد هو أنه يجب عليك تعيين القيمة يدويًا لكل عضو.

function _enum(list) {       
  for (var key in list) {
    list[list[key] = list[key]] = key;
  }
  return Object.freeze(list);
}

var Color = _enum({
  Red: 0,
  Green: 5,
  Blue: 2
});

// Color → {0: "Red", 2: "Blue", 5: "Green", "Red": 0, "Green": 5, "Blue": 2}
// Color.Red → 0
// Color.Green → 5
// Color.Blue → 2
// Color[5] → Green
// Color.Blue > Color.Green → false


وإليك mixond لإنشاء تعداد باستخدام سلسلة. في حين أن هذا الإصدار أكثر انخفاضاً ، فإنه يقوم بالترقيم تلقائيًا بالنسبة لك. جميع أساليب towash المستخدمة في هذا المثال لديها ما يعادل جافا سكريبت العادية ، لذلك يمكنك تبديلها بسهولة إذا كنت تريد.

function enum() {
    var key, val = -1, list = {};
    _.reduce(_.toArray(arguments), function(result, kvp) {    
        kvp = kvp.split("=");
        key = _.trim(kvp[0]);
        val = _.parseInt(kvp[1]) || ++val;            
        result[result[val] = key] = val;
        return result;
    }, list);
    return Object.freeze(list);
}    

// Add enum to lodash 
_.mixin({ "enum": enum });

var Color = _.enum(
    "Red",
    "Green",
    "Blue = 5",
    "Yellow",
    "Purple = 20",
    "Gray"
);

// Color.Red → 0
// Color.Green → 1
// Color.Blue → 5
// Color.Yellow → 6
// Color.Purple → 20
// Color.Gray → 21
// Color[5] → Blue



إذا كنت تستخدم Backbone ، فيمكنك الحصول على وظيفة التعداد الكامل (البحث عن طريق id ، والاسم ، والأعضاء المخصصين) مجانًا باستخدام 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()



هذا ليس جوابًا كبيرًا ، لكنني أقول أنه يعمل بشكل جيد ، شخصيًا

بعد قولي هذا ، بما أنه لا يهم ما هي القيم (التي استخدمتها 0 ، 1 ، 2) ، فسوف أستخدم سلسلة ذات معنى في حال أردت إخراج القيمة الحالية.




لقد قمت للتو بنشر حزمة NPM gen_enum تسمح لك بإنشاء بنية بيانات Enum في Javascript بسرعة:

var genEnum = require('gen_enum');

var AppMode = genEnum('SIGN_UP, LOG_IN, FORGOT_PASSWORD');
var curMode = AppMode.LOG_IN;
console.log(curMode.isLogIn()); // output true 
console.log(curMode.isSignUp()); // output false 
console.log(curMode.isForgotPassword()); // output false 

شيء واحد لطيف حول هذه الأداة الصغيرة في البيئة الحديثة (بما في ذلك nodejs و IE 9+ المستعرضات) الكائن Enum الذي تم إرجاعه غير قابل للتغيير.

لمزيد من المعلومات يرجى التحقق https://github.com/greenlaw110/enumjs

التحديثات

أنا حزمة gen_enum عفا عليها الزمن ودمج وظيفة في حزمة constjs ، والتي توفر المزيد من الميزات بما في ذلك الأشياء الثابتة ، إلغاء تسلسل سلسلة JSON ، ثوابت سلسلة وتوليد صورة نقطية الخ. Checkout constjs لمزيد من المعلومات

للترقية من gen_enum إلى constjs فقط قم بتغيير العبارة

var genEnum = require('gen_enum');

إلى

var genEnum = require('constjs').enum;



أجوبتك معقدة للغاية

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



توصلت إلى this النهج الذي تم تصميمه على غرار التعدادات في جافا. هذه هي آمنة من نوع ، ولذا يمكنك إجراء فحوصات المراجعات أيضًا.

يمكنك تعريف enums مثل هذا:

var Days = Enum.define("Days", ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]);

تشير Days الآن إلى تعداد Days :

Days.Monday instanceof Days; // true

Days.Friday.name(); // "Friday"
Days.Friday.ordinal(); // 4

Days.Sunday === Days.Sunday; // true
Days.Sunday === Days.Friday; // false

Days.Sunday.toString(); // "Sunday"

Days.toString() // "Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } "

Days.values().map(function(e) { return e.name(); }); //["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
Days.values()[4].name(); //"Friday"

Days.fromName("Thursday") === Days.Thursday // true
Days.fromName("Wednesday").name() // "Wednesday"
Days.Friday.fromName("Saturday").name() // "Saturday"

التطبيق:

var Enum = (function () {
    /**
     * Function to define an enum
     * @param typeName - The name of the enum.
     * @param constants - The constants on the enum. Can be an array of strings, or an object where each key is an enum
     * constant, and the values are objects that describe attributes that can be attached to the associated constant.
     */
    function define(typeName, constants) {

        /** Check Arguments **/
        if (typeof typeName === "undefined") {
            throw new TypeError("A name is required.");
        }

        if (!(constants instanceof Array) && (Object.getPrototypeOf(constants) !== Object.prototype)) {

            throw new TypeError("The constants parameter must either be an array or an object.");

        } else if ((constants instanceof Array) && constants.length === 0) {

            throw new TypeError("Need to provide at least one constant.");

        } else if ((constants instanceof Array) && !constants.reduce(function (isString, element) {
                return isString && (typeof element === "string");
            }, true)) {

            throw new TypeError("One or more elements in the constant array is not a string.");

        } else if (Object.getPrototypeOf(constants) === Object.prototype && !Object.keys(constants).reduce(function (isObject, constant) {
                return Object.getPrototypeOf(constants[constant]) === Object.prototype;
            }, true)) {

            throw new TypeError("One or more constants do not have an associated object-value.");

        }

        var isArray = (constants instanceof Array);
        var isObject = !isArray;

        /** Private sentinel-object used to guard enum constructor so that no one else can create enum instances **/
        function __() { };

        /** Dynamically define a function with the same name as the enum we want to define. **/
        var __enum = new Function(["__"],
            "return function " + typeName + "(sentinel, name, ordinal) {" +
                "if(!(sentinel instanceof __)) {" +
                    "throw new TypeError(\"Cannot instantiate an instance of " + typeName + ".\");" +
                "}" +

                "this.__name = name;" +
                "this.__ordinal = ordinal;" +
            "}"
        )(__);

        /** Private objects used to maintain enum instances for values(), and to look up enum instances for fromName() **/
        var __values = [];
        var __dict = {};

        /** Attach values() and fromName() methods to the class itself (kind of like static methods). **/
        Object.defineProperty(__enum, "values", {
            value: function () {
                return __values;
            }
        });

        Object.defineProperty(__enum, "fromName", {
            value: function (name) {
                var __constant = __dict[name]
                if (__constant) {
                    return __constant;
                } else {
                    throw new TypeError(typeName + " does not have a constant with name " + name + ".");
                }
            }
        });

        /**
         * The following methods are available to all instances of the enum. values() and fromName() need to be
         * available to each constant, and so we will attach them on the prototype. But really, they're just
         * aliases to their counterparts on the prototype.
         */
        Object.defineProperty(__enum.prototype, "values", {
            value: __enum.values
        });

        Object.defineProperty(__enum.prototype, "fromName", {
            value: __enum.fromName
        });

        Object.defineProperty(__enum.prototype, "name", {
            value: function () {
                return this.__name;
            }
        });

        Object.defineProperty(__enum.prototype, "ordinal", {
            value: function () {
                return this.__ordinal;
            }
        });

        Object.defineProperty(__enum.prototype, "valueOf", {
            value: function () {
                return this.__name;
            }
        });

        Object.defineProperty(__enum.prototype, "toString", {
            value: function () {
                return this.__name;
            }
        });

        /**
         * If constants was an array, we can the element values directly. Otherwise, we will have to use the keys
         * from the constants object.
         */
        var _constants = constants;
        if (isObject) {
            _constants = Object.keys(constants);
        }

        /** Iterate over all constants, create an instance of our enum for each one, and attach it to the enum type **/
        _constants.forEach(function (name, ordinal) {
            // Create an instance of the enum
            var __constant = new __enum(new __(), name, ordinal);

            // If constants was an object, we want to attach the provided attributes to the instance.
            if (isObject) {
                Object.keys(constants[name]).forEach(function (attr) {
                    Object.defineProperty(__constant, attr, {
                        value: constants[name][attr]
                    });
                });
            }

            // Freeze the instance so that it cannot be modified.
            Object.freeze(__constant);

            // Attach the instance using the provided name to the enum type itself.
            Object.defineProperty(__enum, name, {
                value: __constant
            });

            // Update our private objects
            __values.push(__constant);
            __dict[name] = __constant;
        });

        /** Define a friendly toString method for the enum **/
        var string = typeName + " { " + __enum.values().map(function (c) {
                return c.name();
            }).join(", ") + " } ";

        Object.defineProperty(__enum, "toString", {
            value: function () {
                return string;
            }
        });

        /** Freeze our private objects **/
        Object.freeze(__values);
        Object.freeze(__dict);

        /** Freeze the prototype on the enum and the enum itself **/
        Object.freeze(__enum.prototype);
        Object.freeze(__enum);

        /** Return the enum **/
        return __enum;
    }

    return {
        define: define
    }

})();



طريقة سريعة وبسيطة هي:

var Colors = function(){
return {
    'WHITE':0,
    'BLACK':1,
    'RED':2,
    'GREEN':3
    }
}();

console.log(Colors.WHITE)  //this prints out "0"



في معظم المتصفحات الحديثة ، هناك نوع بيانات symbol البدائي الذي يمكن استخدامه لإنشاء التعداد. سيضمن ضمان سلامة التعداد ، حيث أن كل قيمة رمزية مضمونة بجافا سكريبت لتكون فريدة ، أي Symbol() != Symbol() . فمثلا:

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

لتبسيط التصحيح ، يمكنك إضافة وصف لقيم التعداد:

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

عرض Plunker

على GitHub يمكنك العثور على غلاف يبسط الكود المطلوب لتهيئة التعداد:

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



es7 way, (iterator, freeze), usage:

const ThreeWiseMen = new Enum('Melchior', 'Caspar', 'Balthazar')

for (let name of ThreeWiseMen)
    console.log(name)


// with a given key
let key = ThreeWiseMen.Melchior

console.log(key in ThreeWiseMen) // true (string conversion, also true: 'Melchior' in ThreeWiseMen)

for (let entry from key.enum)
     console.log(entry)


// prevent alteration (throws TypeError in strict mode)
ThreeWiseMen.Me = 'Me too!'
ThreeWiseMen.Melchior.name = 'Foo'

code:

class EnumKey {

    constructor(props) { Object.freeze(Object.assign(this, props)) }

    toString() { return this.name }

}

export class Enum {

    constructor(...keys) {

        for (let [index, key] of keys.entries()) {

            Object.defineProperty(this, key, {

                value: new EnumKey({ name:key, index, enum:this }),
                enumerable: true,

            })

        }

        Object.freeze(this)

    }

    *[Symbol.iterator]() {

        for (let key of Object.keys(this))
            yield this[key]

    }

    toString() { return [...this].join(', ') }

}



يمكنك فعل شيء كهذا

function Enum(){
  this.add.apply(this,arguments);
}

Enum.prototype.add = function(){
  for (var i in arguments) {
    this[arguments[i]] = new String(arguments[i]);
  }
};
Enum.prototype.toList = function(){
  return Object.keys(this)
};

var STATUS = new Enum("CLOSED","PENDING");


var STATE = new Enum("CLOSED","PENDING");

STATE.CLOSED === STATUS.CLOSED  // false;
STATE.CLOSED === "CLOSED"  // false;
STATE.CLOSED.toString() === "CLOSED"  // true;

As defined in this library. https://github.com/webmodule/foo/blob/master/foo.js#L217




هذا هو الحل الذي أستخدمه.

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

وتحدد التعدادات الخاصة بك على النحو التالي:

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

وهذه هي الطريقة التي تدخل بها التعدادات الخاصة بك:

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

عادة ما أستخدم آخر 2 طريقة لرسم التعدادات من كائنات الرسالة.

بعض المزايا لهذا النهج:

  • من السهل أن تعلن التعداد
  • من السهل الوصول إلى التعداد الخاص بك
  • يمكن أن يكون التعداد الخاص بك أنواعًا معقدة
  • يحتوي الصف Enum على بعض التخزين المؤقت النقابي إذا كنت تستخدم getByValue كثيرًا

بعض العيوب:

  • بعض إدارة الذاكرة الفوضوي مستمرة هناك ، حيث أحتفظ بالإشارات إلى التعدادات
  • لا يوجد حتى الآن نوع السلامة



لا يدعم IE8 أسلوب التجميد ().
المصدر: http://kangax.github.io/compat-table/es5/ ، انقر على "إظهار المتصفحات القديمة؟" في الأعلى ، وتحقق من IE8 وتجمد تقاطع الصفوف.

في مشروع الألعاب الحالي ، استخدمت أدناه ، حيث لا يزال عدد قليل من العملاء يستخدمون IE8:

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

يمكننا أيضًا القيام بما يلي:

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

أو حتى هذا:

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

أما الطريقة الأخيرة ، فيبدو أنها الأكثر كفاءة بالنسبة إلى السلسلة ، فهي تقلل من إجمالي النطاق الترددي إذا كان لديك خادم وعميل يتبادلان هذه البيانات.
بالطبع ، من واجبك الآن التأكد من عدم وجود تعارض في البيانات (RE، EX ، إلخ. يجب أن تكون فريدة ، يجب أن تكون 1 ، 2 ، إلخ. فريدة من نوعها). لاحظ أنك تحتاج إلى الحفاظ على هذه إلى الأبد للتوافق مع الإصدارات السابقة.

مهمة:

var wildType = CONST_WILD_TYPES.REGULAR;

المقارنة:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}



لقد لعبت مع هذا ، كما أحب التعداد الخاص بي. =)

باستخدام Object.defineProperty أعتقد أنني توصلت إلى حل قابل للبقاء إلى حد ما.

وإليك jsfiddle: http://jsfiddle.net/ZV4A6/

باستخدام هذه الطريقة .. يجب عليك (من الناحية النظرية) أن تكون قادرة على استدعاء وتعريف قيم التعداد لأي كائن ، دون التأثير على سمات أخرى لهذا الكائن.

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

بسبب السمة writable:false يجب أن يجعلها آمنة.

لذلك يجب أن تتمكن من إنشاء كائن مخصص ، ثم استدعاء Enum() عليه. تبدأ القيم المعينة عند 0 والزيادة لكل عنصر.

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



It's easy to use, I think. https://.com/a/32245370/4365315

var A = {a:11, b:22}, 
enumA = new TypeHelper(A);

if(enumA.Value === A.b || enumA.Key === "a"){ 
... 
}

var keys = enumA.getAsList();//[object, object]

//set
enumA.setType(22, false);//setType(val, isKey)

enumA.setType("a", true);

enumA.setTypeByIndex(1);

تحديث:

There is my helper codes( TypeHelper ).

var Helper = {
    isEmpty: function (obj) {
        return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
    },

    isObject: function (obj) {
        return (typeof obj === 'object');
    },

    sortObjectKeys: function (object) {
        return Object.keys(object)
            .sort(function (a, b) {
                c = a - b;
                return c
            });
    },
    containsItem: function (arr, item) {
        if (arr && Array.isArray(arr)) {
            return arr.indexOf(item) > -1;
        } else {
            return arr === item;
        }
    },

    pushArray: function (arr1, arr2) {
        if (arr1 && arr2 && Array.isArray(arr1)) {
            arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
        }
    }
};
function TypeHelper() {
    var _types = arguments[0],
        _defTypeIndex = 0,
        _currentType,
        _value,
        _allKeys = Helper.sortObjectKeys(_types);

    if (arguments.length == 2) {
        _defTypeIndex = arguments[1];
    }

    Object.defineProperties(this, {
        Key: {
            get: function () {
                return _currentType;
            },
            set: function (val) {
                _currentType.setType(val, true);
            },
            enumerable: true
        },
        Value: {
            get: function () {
                return _types[_currentType];
            },
            set: function (val) {
                _value.setType(val, false);
            },
            enumerable: true
        }
    });
    this.getAsList = function (keys) {
        var list = [];
        _allKeys.forEach(function (key, idx, array) {
            if (key && _types[key]) {

                if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) {
                    var json = {};
                    json.Key = key;
                    json.Value = _types[key];
                    Helper.pushArray(list, json);
                }
            }
        });
        return list;
    };

    this.setType = function (value, isKey) {
        if (!Helper.isEmpty(value)) {
            Object.keys(_types).forEach(function (key, idx, array) {
                if (Helper.isObject(value)) {
                    if (value && value.Key == key) {
                        _currentType = key;
                    }
                } else if (isKey) {
                    if (value && value.toString() == key.toString()) {
                        _currentType = key;
                    }
                } else if (value && value.toString() == _types[key]) {
                    _currentType = key;
                }
            });
        } else {
            this.setDefaultType();
        }
        return isKey ? _types[_currentType] : _currentType;
    };

    this.setTypeByIndex = function (index) {
        for (var i = 0; i < _allKeys.length; i++) {
            if (index === i) {
                _currentType = _allKeys[index];
                break;
            }
        }
    };

    this.setDefaultType = function () {
        this.setTypeByIndex(_defTypeIndex);
    };

    this.setDefaultType();
}

var TypeA = {
    "-1": "Any",
    "2": "2L",
    "100": "100L",
    "200": "200L",
    "1000": "1000L"
};

var enumA = new TypeHelper(TypeA, 4);

document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setType("200L", false);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

enumA.setDefaultType();
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");


enumA.setTypeByIndex(1);
document.writeln("Key = ", enumA.Key,", Value = ", enumA.Value, "<br>");

document.writeln("is equals = ", (enumA.Value == TypeA["2"]));




استكمال : شكرا لجميع upvotes الجميع ، لكنني لا أعتقد أن جوابي أدناه هو أفضل طريقة لكتابة enums في جافا سكريبت بعد الآن. شاهد منشور مدونتي لمزيد من التفاصيل: Enums في Javascript .

يكون التنبيه ممكنًا بالفعل:

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

بدلا من ذلك ، يمكنك جعل قيم الكائنات ، بحيث يمكنك الحصول على الكعكة وأكلها أيضا:

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 ، لأنها لغة ديناميكية ، من الممكن إضافة قيم التعداد إلى المجموعة التالية:

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

تذكر أن حقول التعداد (القيمة والاسم والتعليمات البرمجية في هذا المثال) ليست ضرورية لفحص الهوية وهي موجودة فقط من أجل الراحة. كما لا يحتاج اسم خاصية الحجم نفسه إلى ضمنية ، ولكن يمكن أيضًا تعيينه ديناميكيًا. لذا لنفترض أنك تعرف فقط اسم قيمة التعداد الجديدة ، فلا يزال بإمكانك إضافتها دون مشاكل:

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

بالطبع هذا يعني أنه لم يعد من الممكن إجراء بعض الافتراضات (تلك القيمة تمثل الترتيب الصحيح للحجم على سبيل المثال).

تذكر ، في Javascript ، كائن مثل الخريطة أو hashtable. مجموعة من أزواج الاسم-القيمة. يمكنك التكرار عبرها أو التلاعب بها دون معرفة الكثير عنها مسبقًا.

EG:

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

و btw ، إذا كنت مهتمًا بمساحات الأسماء ، فقد ترغب في إلقاء نظرة على حلّي لمساحة أسماء بسيطة وفعالة وإدارة قوية للارتباط بجافا سكريبت: Packages JS




ماذا لو كنت تعرف أن هذا النوع سيكون enum ، لكنك لا تعرف ما هو النوع الدقيق في وقت التحويل البرمجي؟

public class EnumHelper
{
    public static IEnumerable<T> GetValues<T>()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }

    public static IEnumerable getListOfEnum(Type type)
    {
        MethodInfo getValuesMethod = typeof(EnumHelper).GetMethod("GetValues").MakeGenericMethod(type);
        return (IEnumerable)getValuesMethod.Invoke(null, null);
    }
}

الأسلوب getListOfEnum يستخدم انعكاس لأخذ أي نوع التعداد وإرجاع IEnumerable لجميع قيم التعداد.

الاستعمال:

Type myType = someEnumValue.GetType();

IEnumerable resultEnumerable = getListOfEnum(myType);

foreach (var item in resultEnumerable)
{
    Console.WriteLine(String.Format("Item: {0} Value: {1}",item.ToString(),(int)item));
}




javascript enums