etc./StackOverFlow

내 열거형 정의가 JavaScript에서 변경되지 않는다는 것을 어떻게 보장할 수 있습니까?

청렴결백한 만능 재주꾼 2021. 11. 24. 06:14
반응형

질문자 :David Citron


다음은 객체가 JavaScript에서 열거형이 가진 모든 특성을 충족하도록 만들까요? 다음과 같은 것:

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

아니면 내가 할 수있는 다른 방법이 있습니까?



1.8.5부터 객체를 봉인하고 고정 할 수 있으므로 위를 다음과 같이 정의합니다.

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

또는

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

그리고 짜잔! JS 열거형.

그러나 이것은 종종 열거형의 주요 목표인 바람직하지 않은 값을 변수에 할당하는 것을 방지하지 않습니다.

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

더 강력한 유형 안전성을 보장하는 한 가지 방법(enum 또는 기타 사용)은 TypeScript 또는 Flow 와 같은 도구를 사용하는 것입니다.

따옴표는 필요하지 않지만 일관성을 위해 보관했습니다.


Artur Czajka

이것은 많은 대답은 아니지만 개인적으로 잘 작동한다고 말하고 싶습니다.

값이 무엇인지는 중요하지 않기 때문에(0, 1, 2를 사용함) 현재 값을 출력하려는 경우를 대비하여 의미 있는 문자열을 사용합니다.


Gareth

업데이트

모든 사람에게 찬성 투표를 해주셔서 감사합니다. 하지만 아래 제 답변이 더 이상 JavaScript로 열거형을 작성하는 가장 좋은 방법이라고 생각하지 않습니다. 자세한 내용은 내 블로그 게시물( JavaScript의 Enums) 을 참조하세요.


이름 경고는 이미 가능합니다.

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

또는 values 객체를 만들 수 있으므로 케이크를 가지고 먹을 수도 있습니다.

 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에서 객체는 또는 해시 테이블과 같습니다 . 이름-값 쌍의 집합입니다. 사전에 많은 정보를 모른 채 반복하거나 조작할 수 있습니다.

예시

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

그건 그렇고, 네임스페이스에 관심이 있다면 JavaScript에 대한 간단하지만 강력한 네임스페이스 및 종속성 관리에 대한 제 솔루션을 살펴보고 싶을 것입니다. Packages JS


Stijn de Witt

결론: 당신은 할 수 없습니다.

당신은 그것을 속일 수 있지만 당신은 유형 안전을 얻지 못할 것입니다. 일반적으로 이것은 정수 값에 매핑된 문자열 값의 간단한 사전을 만들어 수행됩니다. 예를 들어:

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

이 접근 방식의 문제? 실수로 열거자를 재정의하거나 실수로 열거형 값이 중복될 수 있습니다. 예를 들어:

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

편집하다

Artur Czajka의 Object.freeze는 어떻습니까? 월요일을 목요일로 설정하는 것을 방지하기 위해 작동하지 않습니까? – 프라이 쿼드

물론 Object.freeze 는 내가 불평했던 문제를 완전히 해결할 것입니다. 위의 글을 썼을 때 Object.freeze 는 실제로 존재하지 않았다는 것을 모두에게 상기시키고 싶습니다.

자.... 이제 아주 흥미로운 가능성이 열립니다.

편집 2
다음은 열거형을 만들기 위한 아주 좋은 라이브러리입니다.

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

열거형의 모든 유효한 사용에 적합하지 않을 수 있지만 매우 긴 방법을 사용합니다.


Randolpho

다음은 우리 모두가 원하는 것입니다.

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

Andre 'Fi'

대부분의 최신 브라우저에는 열거형을 만드는 데 사용할 수 있는 기호 기본 데이터 유형이 있습니다. 각 기호 값이 JavaScript에 의해 고유한 것으로 보장되므로 열거형의 유형 안전성이 보장됩니다 Symbol() != Symbol() . 예를 들어:

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

디버깅을 단순화하기 위해 열거형 값에 설명을 추가할 수 있습니다.

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

플런커 데모

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

Vitalii Fedorenko

-

바로 문제로 넘어가겠습니다. 파일 크기입니다. 여기에 나열된 다른 모든 답변은 축소된 코드를 극도로 부풀려줍니다. 축소, 성능, 코드 가독성, 대규모 프로젝트 관리 및 많은 코드 편집기에서 구문 힌트를 통해 코드 크기를 최대한 줄이기 위해서는 밑줄 표기법 변수가 열거를 수행하는 올바른 방법임을 제시합니다.


밑줄 표기법 변수

위의 차트와 아래의 예에서 볼 수 있듯이 다음은 쉽게 시작할 수 있는 5단계입니다.

  1. 열거 그룹의 이름을 결정합니다. 열거의 목적이나 열거의 항목을 설명할 수 있는 명사를 생각하십시오. 예를 들어, 사용자가 선택할 수 있는 색상을 나타내는 열거 그룹의 이름은 COLORS보다 COLORCHOICES로 더 잘 지정될 수 있습니다.
  2. 그룹의 열거가 상호 배타적인지 독립적인지 결정합니다. 상호 배타적인 경우 각 열거 변수 이름을 ENUM_ 시작합니다. 독립적이거나 병렬인 경우 INDEX_ 사용하십시오.
  3. ENUM_ 또는 INDEX_ 시작하는 새 로컬 변수를 만들고 그룹 이름, 밑줄, 속성에 대한 고유한 친숙한 이름을 차례로 만듭니다.
  4. ENUMLENGTH_ , ENUMLEN_ , INDEXLENGTH_ 또는 INDEXLEN_ LEN_ 또는 LENGTH_ 가 개인 취향인지 여부) 열거 변수를 추가하십시오. 열거형에 추가 항목을 추가하고 이 값을 증가시켜도 코드가 손상되지 않도록 코드에서 가능한 한 이 변수를 사용해야 합니다.
  5. 말을이 페이지에 대한 의견이 있습니다 0에서 시작하여, 마지막으로보다 각 연속 열거 변수에 값을 부여 0 열거 값 때문으로 사용해서는 안가 0 == null , 0 == false , 0 == "" , 그리고 다른 JS 광기. 이 문제를 피하고 동시에 성능을 높이려면 항상 === typeof (ex typeof X == "string" )를 제외하고 코드에 == 나타나지 않도록 하십시오. === 를 사용한 수년 동안 저는 0을 열거형 값으로 사용하는 데 문제가 발생한 적이 없습니다. 여전히 INDEX_ 많은 경우에 성능 저하 없이 ENUM_ 열거( ENUM_ 1 시작 값으로 사용할 수 있습니다.
 const ENUM_COLORENUM_RED = 0; const ENUM_COLORENUM_GREEN = 1; const ENUM_COLORENUM_BLUE = 2; const ENUMLEN_COLORENUM = 3; // later on if(currentColor === ENUM_COLORENUM_RED) { // whatever }

여기에 사용할 때 내가 기억하는 방법이다 INDEX_ 때 사용하는 방법과 ENUM_ :

 // Precondition: var arr = []; // arr[INDEX_] = ENUM_;

그러나 ENUM_ 은 특정 상황에서 각 항목의 발생 횟수를 계산할 때와 같이 인덱스로 적절할 수 있습니다.

 const ENUM_PET_CAT = 0, ENUM_PET_DOG = 1, ENUM_PET_RAT = 2, ENUMLEN_PET = 3; var favoritePets = [ENUM_PET_CAT, ENUM_PET_DOG, ENUM_PET_RAT, ENUM_PET_DOG, ENUM_PET_DOG, ENUM_PET_CAT, ENUM_PET_RAT, ENUM_PET_CAT, ENUM_PET_DOG]; var petsFrequency = []; for (var i=0; i<ENUMLEN_PET; i=i+1|0) petsFrequency[i] = 0; for (var i=0, len=favoritePets.length|0, petId=0; i<len; i=i+1|0) petsFrequency[petId = favoritePets[i]|0] = (petsFrequency[petId]|0) + 1|0; console.log({ "cat": petsFrequency[ENUM_PET_CAT], "dog": petsFrequency[ENUM_PET_DOG], "rat": petsFrequency[ENUM_PET_RAT] });

위의 코드에서 새로운 종류의 애완동물을 추가하는 것은 정말 쉽습니다 ENUMLEN_PET ENUM_PET_RAT 을 업데이트하면 됩니다. 다른 열거 시스템에 새 항목을 추가하는 것이 더 어렵고 버그가 있을 수 있습니다.


또한 이 열거형 구문을 사용하면 아래와 같이 명확하고 간결한 클래스 확장이 가능합니다. 클래스를 확장하려면 상위 클래스 LEN_ 항목에 증가하는 숫자를 추가하십시오. 그런 다음 하위 클래스가 나중에 더 확장될 수 있도록 LEN_ 항목으로 하위 클래스를 완성합니다.

추가 확장 다이어그램

 (function(window){ "use strict"; var parseInt = window.parseInt; // use INDEX_ when representing the index in an array instance const INDEX_PIXELCOLOR_TYPE = 0, // is a ENUM_PIXELTYPE INDEXLEN_PIXELCOLOR = 1, INDEX_SOLIDCOLOR_R = INDEXLEN_PIXELCOLOR+0, INDEX_SOLIDCOLOR_G = INDEXLEN_PIXELCOLOR+1, INDEX_SOLIDCOLOR_B = INDEXLEN_PIXELCOLOR+2, INDEXLEN_SOLIDCOLOR = INDEXLEN_PIXELCOLOR+3, INDEX_ALPHACOLOR_R = INDEXLEN_PIXELCOLOR+0, INDEX_ALPHACOLOR_G = INDEXLEN_PIXELCOLOR+1, INDEX_ALPHACOLOR_B = INDEXLEN_PIXELCOLOR+2, INDEX_ALPHACOLOR_A = INDEXLEN_PIXELCOLOR+3, INDEXLEN_ALPHACOLOR = INDEXLEN_PIXELCOLOR+4, // use ENUM_ when representing a mutually-exclusive species or type ENUM_PIXELTYPE_SOLID = 0, ENUM_PIXELTYPE_ALPHA = 1, ENUM_PIXELTYPE_UNKNOWN = 2, ENUMLEN_PIXELTYPE = 2; function parseHexColor(inputString) { var rawstr = inputString.trim().substring(1); var result = []; if (rawstr.length === 8) { result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA; result[INDEX_ALPHACOLOR_R] = parseInt(rawstr.substring(0,2), 16); result[INDEX_ALPHACOLOR_G] = parseInt(rawstr.substring(2,4), 16); result[INDEX_ALPHACOLOR_B] = parseInt(rawstr.substring(4,6), 16); result[INDEX_ALPHACOLOR_A] = parseInt(rawstr.substring(4,6), 16); } else if (rawstr.length === 4) { result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_ALPHA; result[INDEX_ALPHACOLOR_R] = parseInt(rawstr[0], 16) * 0x11; result[INDEX_ALPHACOLOR_G] = parseInt(rawstr[1], 16) * 0x11; result[INDEX_ALPHACOLOR_B] = parseInt(rawstr[2], 16) * 0x11; result[INDEX_ALPHACOLOR_A] = parseInt(rawstr[3], 16) * 0x11; } else if (rawstr.length === 6) { result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID; result[INDEX_SOLIDCOLOR_R] = parseInt(rawstr.substring(0,2), 16); result[INDEX_SOLIDCOLOR_G] = parseInt(rawstr.substring(2,4), 16); result[INDEX_SOLIDCOLOR_B] = parseInt(rawstr.substring(4,6), 16); } else if (rawstr.length === 3) { result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_SOLID; result[INDEX_SOLIDCOLOR_R] = parseInt(rawstr[0], 16) * 0x11; result[INDEX_SOLIDCOLOR_G] = parseInt(rawstr[1], 16) * 0x11; result[INDEX_SOLIDCOLOR_B] = parseInt(rawstr[2], 16) * 0x11; } else { result[INDEX_PIXELCOLOR_TYPE] = ENUM_PIXELTYPE_UNKNOWN; } return result; } // the red component of green console.log(parseHexColor("#0f0")[INDEX_SOLIDCOLOR_R]); // the alpha of transparent purple console.log(parseHexColor("#f0f7")[INDEX_ALPHACOLOR_A]); // the enumerated array for turquoise console.log(parseHexColor("#40E0D0")); })(self);

(길이: 2,450바이트)

어떤 사람들은 이것이 다른 솔루션보다 덜 실용적이라고 말할 수 있습니다. 많은 공간을 낭비하고 작성하는 데 오랜 시간이 걸리며 설탕 구문으로 코팅되지 않습니다. 코드를 축소하지 않으면 그 사람들이 옳을 것입니다. 그러나 합리적인 사람은 최종 제품에 축소되지 않은 코드를 남기지 않을 것입니다. 이 축소를 위해 Closure Compiler는 내가 아직 찾지 못한 최고입니다. 온라인 액세스는 여기 에서 찾을 수 있습니다. 클로저 컴파일러는 이 모든 열거 데이터를 가져와서 인라인할 수 있으므로 Javascript를 매우 작고 매우 빠르게 실행할 수 있습니다. 따라서 클로저 컴파일러로 축소하십시오. 관찰하다.


클로저 컴파일러는 다른 어떤 자바스크립트 축소기의 능력을 훨씬 능가하는 추론을 통해 꽤 놀라운 최적화를 수행할 수 있습니다. 클로저 컴파일러는 고정 값으로 설정된 기본 변수를 인라인할 수 있습니다. 또한 클로저 컴파일러는 이러한 인라인 값을 기반으로 추론을 수행하고 if 문 및 루프에서 사용되지 않는 블록을 제거할 수 있습니다.

클로저 컴파일러를 통한 코드 짜기

 'use strict';(function(e){function d(a){a=a.trim().substring(1);var b=[];8===a.length?(b[0]=1,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16),b[4]=c(a.substring(4,6),16)):4===a.length?(b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16),b[4]=17*c(a[3],16)):6===a.length?(b[0]=0,b[1]=c(a.substring(0,2),16),b[2]=c(a.substring(2,4),16),b[3]=c(a.substring(4,6),16)):3===a.length?(b[0]=0,b[1]=17*c(a[0],16),b[2]=17*c(a[1],16),b[3]=17*c(a[2],16)):b[0]=2;return b}var c= e.parseInt;console.log(d("#0f0")[1]);console.log(d("#f0f7")[4]);console.log(d("#40E0D0"))})(self);

(길이: 605바이트)

Closure Compiler는 더 똑똑하게 코딩하고 코드를 잘 구성한 것에 대해 보상합니다. 많은 축소기가 조직화된 코드를 더 큰 축소된 파일 크기로 처벌하는 반면, Closure Compiler는 트릭을 사용하면 더 작은 파일 크기를 출력하기 위해 모든 깨끗함과 온전함을 선별할 수 있기 때문입니다. 변수 이름 열거처럼. 이것이 바로 코딩의 성배입니다. 더 작은 축소 크기로 코드를 지원하고 더 나은 프로그래밍 습관을 훈련하여 마음을 돕는 도구입니다.


이제 이러한 열거가 없으면 해당 파일이 얼마나 큰지 봅시다.


열거를 사용하지 않은 소스 (길이: 1,973바이트(열거된 코드보다 477바이트 짧음!))
열거를 사용하지 않고 축소 (길이: 843바이트( 열거된 코드보다 238바이트 큼))

코드 크기 차트



보시다시피, 열거가 없으면 더 큰 축소 코드를 사용하는 대신 소스 코드가 더 짧습니다. 나는 당신에 대해 모른다; 그러나 나는 소스 코드를 최종 제품에 통합하지 않는다는 것을 확실히 알고 있습니다. 따라서 이러한 형식의 열거는 축소된 파일 크기를 더 작게 만드는 점에서 훨씬 우수합니다.


이 열거 형식의 또 다른 장점은 축소된 코드 크기를 희생하지 않고 대규모 프로젝트를 쉽게 관리하는 데 사용할 수 있다는 것입니다. 다른 많은 사람들과 함께 대규모 프로젝트에서 작업할 때 공동 버그 수정을 위해 코드의 원래 작성자를 빠르게 식별할 수 있도록 코드를 만든 사람과 함께 변수 이름을 명시적으로 표시하고 레이블을 지정하는 것이 유용할 수 있습니다.

 // JG = Jack Giffin const ENUM_JG_COLORENUM_RED = 0, ENUM_JG_COLORENUM_GREEN = 1, ENUM_JG_COLORENUM_BLUE = 2, ENUMLEN_JG_COLORENUM = 3; // later on if(currentColor === ENUM_JG_COLORENUM_RED) { // whatever } // PL = Pepper Loftus // BK = Bob Knight const ENUM_PL_ARRAYTYPE_UNSORTED = 0, ENUM_PL_ARRAYTYPE_ISSORTED = 1, ENUM_BK_ARRAYTYPE_CHUNKED = 2, // added by Bob Knight ENUM_JG_ARRAYTYPE_INCOMPLETE = 3, // added by jack giffin ENUMLEN_PL_COLORENUM = 4; // later on if( randomArray === ENUM_PL_ARRAYTYPE_UNSORTED || randomArray === ENUM_BK_ARRAYTYPE_CHUNKED ) { // whatever }

또한 이러한 형태의 열거는 축소 후에도 훨씬 빠릅니다. 일반 명명된 속성에서 브라우저는 해시맵을 사용하여 개체에서 속성이 있는 위치를 찾아야 합니다. JIT 컴파일러는 개체에서 이 위치를 지능적으로 캐시하지만 개체에서 하위 속성을 삭제하는 것과 같은 특수한 경우로 인해 여전히 엄청난 오버헤드가 있습니다.

그러나 연속적이지 않은 비희소 정수 인덱스 PACKED_ELEMENTS 배열을 사용하면 내부 배열에 있는 값의 인덱스가 이미 지정되어 있기 때문에 브라우저에서 해당 오버헤드의 대부분을 건너뛸 수 있습니다. 예, ECMAScript 표준에 따르면 모든 속성은 문자열로 처리되어야 합니다. 그럼에도 불구하고 ECMAScript 표준의 이러한 측면은 모든 브라우저가 배열의 숫자 인덱스에 대한 특수 최적화를 가지고 있기 때문에 성능에 대해 매우 오해의 소지가 있습니다.

 /// Hashmaps are slow, even with JIT juice var ref = {}; ref.count = 10; ref.value = "foobar";

위의 코드를 아래의 코드와 비교하십시오.

 /// Arrays, however, are always lightning fast const INDEX_REFERENCE_COUNT = 0; const INDEX_REFERENCE_VALUE = 1; const INDEXLENGTH_REFERENCE = 2; var ref = []; ref[INDEX_REFERENCE_COUNT] = 10; ref[INDEX_REFERENCE_VALUE] = "foobar";

열거형이 일반 개체가 있는 코드보다 훨씬 긴 것처럼 보이는 코드에 이의를 제기할 수 있지만 모양은 속일 수 있습니다. 에픽 클로저 컴파일러를 사용할 때 소스 코드 크기는 출력 크기에 비례하지 않는다는 것을 기억하는 것이 중요합니다. 관찰하다.

 /// Hashmaps are slow, even with JIT juice var a={count:10,value:"foobar"};

열거형이 없는 축소된 코드가 위에 있고 열거형이 있는 축소된 코드가 아래에 있습니다.

 /// Arrays, however, are always lightning fast var a=[10,"foobar"];

위의 예는 성능이 우수할 뿐만 아니라 열거된 코드로 인해 파일 크기도 작아진다는 것을 보여줍니다.


게다가, 이 사람의 개인적인 체리 는 Javascript 모드에서 CodeMirror 텍스트 편집기와 함께 이 형식의 열거를 사용하고 있습니다. CodeMirror의 Javascript 구문 강조 모드는 현재 범위의 지역 변수를 강조 표시합니다. var 키워드로 선언된 경우 변수 이름이 특수 색상(기본적으로 청록색)으로 바뀌기 때문에 변수 이름을 올바르게 입력할 때 즉시 알 수 있습니다. CodeMirror를 사용하지 않더라도 잘못 입력된 열거 이름으로 코드를 실행할 때 [variable name] is not defined 또한 JSLint 및 Closure Compiler와 같은 JavaScript 도구는 열거형 변수 이름을 잘못 입력할 때 알려줍니다. CodeMirror, 브라우저 및 다양한 Javascript 도구를 함께 사용하면 이러한 형식의 열거형 디버깅을 매우 간단하고 쉽게 할 수 있습니다.

CodeMirror 강조 표시 데모

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

위의 스니펫에서 ENUM_COLORENUM_DNE 가 존재하지 않기 때문에 오류 경고를 받았습니다.


이 열거 방법론이 실제로 코드 크기를 줄이는 것뿐만 아니라 성능, 디버깅 및 협업을 위한 가장 좋은 방법이라고 말하는 것이 안전하다고 생각합니다.


Jack G

자바스크립트 프록시 사용

TLDR: 이 클래스를 유틸리티 메서드에 추가하고 코드 전체에서 사용합니다. 기존 프로그래밍 언어의 Enum 동작을 조롱하고 존재하지 않는 열거자에 액세스하거나 열거자를 추가/업데이트하려고 하면 실제로 오류가 발생합니다. Object.freeze() 에 의존할 필요가 없습니다.

 class Enum { constructor(enumObj) { const handler = { get(target, name) { if (typeof target[name] != 'undefined') { 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); } }

그런 다음 클래스를 인스턴스화하여 열거형을 만듭니다.

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

전체 설명:

기존 언어에서 얻을 수 있는 Enum의 매우 유용한 기능 중 하나는 존재하지 않는 열거자에 액세스하려고 하면 폭발(컴파일 시간 오류 발생)된다는 것입니다.

추가 값이 우발적으로/악의적으로 추가되는 것을 방지하기 위해 조롱된 열거형 구조를 고정하는 것 외에 다른 답변은 열거형의 고유 기능을 다루지 않습니다.

아시다시피 JavaScript에서 존재 undefined 반환되고 코드가 폭발하지 않습니다. 열거자는 미리 정의된 상수(예: 요일)이므로 열거자가 정의되지 않아야 하는 경우가 있어서는 안 됩니다.

undefined 것을 반환하는 JavaScript의 동작은 실제로 언어의 매우 강력한 기능이지만 전통적인 Enum 구조를 조롱하려고 할 때 원하는 기능이 아닙니다.

이것은 프록시 객체가 빛나는 곳입니다. 프록시는 ES6(ES2015)의 도입과 함께 해당 언어로 표준화되었습니다. MDN의 설명은 다음과 같습니다.

Proxy 개체는 기본 작업(예: 속성 조회, 할당, 열거, 함수 호출 등)에 대한 사용자 지정 동작을 정의하는 데 사용됩니다.

웹 서버 프록시와 유사하게 JavaScript 프록시는 객체에 대한 작업을 가로챌 수 있으며("트랩"을 사용하여 원하는 경우 후크로 호출) 완료하기 전에 다양한 검사, 작업 및/또는 조작을 수행할 수 있습니다. 어떤 경우에는 존재하지 않는 열거자를 참조하려고 할 때 정확히 수행하려는 작업을 완전히 중지합니다.

다음은 Proxy 개체를 사용하여 Enum을 모방하는 인위적인 예입니다. 이 예제의 열거자는 표준 HTTP 메서드(예: "GET", "POST" 등)입니다.

 // Class for creating enums (13 lines) // Feel free to add this to your utility library in // your codebase and profit! Note: As Proxies are an ES6 // feature, some browsers/clients may not support it and // you may need to transpile using a service like babel class Enum { // The Enum class instantiates a JavaScript Proxy object. // Instantiating a `Proxy` object requires two parameters, // a `target` object and a `handler`. We first define the handler, // then use the handler to instantiate a Proxy. // A proxy handler is simply an object whose properties // are functions which define the behavior of the proxy // when an operation is performed on it. // For enums, we need to define behavior that lets us check what enumerator // is being accessed and what enumerator is being set. This can be done by // defining "get" and "set" traps. constructor(enumObj) { const handler = { get(target, name) { if (typeof target[name] != 'undefined') { 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') } } // Freeze the target object to prevent modifications return new Proxy(enumObj, handler) } } // Now that we have a generic way of creating Enums, lets create our first Enum! const httpMethods = new Enum({ DELETE: "DELETE", GET: "GET", OPTIONS: "OPTIONS", PATCH: "PATCH", POST: "POST", PUT: "PUT" }) // Sanity checks console.log(httpMethods.DELETE) // logs "DELETE" try { httpMethods.delete = "delete" } catch (e) { console.log("Error: ", e.message) } // throws "Cannot add/update properties on an Enum instance after it is defined" try { console.log(httpMethods.delete) } catch (e) { console.log("Error: ", e.message) } // throws "No such enumerator: delete"


Aside: 프록시가 무엇입니까?

나는 처음에 프록시라는 단어를 어디에서나 보기 시작했을 때 오랫동안 나에게 확실히 이해가 되지 않았던 것을 기억합니다. 지금 그것이 당신이라면 프록시를 일반화하는 쉬운 방법은 소프트웨어, 기관 또는 두 서버, 회사 또는 사람 사이에서 중개자 또는 중개자 역할을 하는 사람으로 생각하는 것입니다.


Govind Rai

나는 내 열거 형을 좋아하기 때문에 이것을 가지고 놀았습니다. =)

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

Duncan

이것은 내가 아는 오래된 것이지만 이후 TypeScript 인터페이스를 통해 구현된 방식은 다음과 같습니다.

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

이것은 당신이 모두에서 찾아 볼 수 있습니다 MyEnum.Bar 1을 반환하고, MyEnum[1] 어떤 관계없이 선언의 순서의 반환 "바".


Rob Hardy

ES7 에서는 정적 속성을 사용하여 우아한 ENUM을 수행할 수 있습니다.

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

그 다음에

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

(리터럴 객체 대신 클래스를 사용하는 것의 장점) 부모 클래스 Enum 있으면 모든 Enum이 해당 클래스 를 확장합니다.

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

Abdennour TOUMI

이것은 내가 사용하는 솔루션입니다.

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

나는 일반적으로 메시지 개체에서 열거형을 매핑하기 위해 마지막 두 가지 방법을 사용합니다.

이 접근 방식의 몇 가지 장점:

  • 열거형을 선언하기 쉬움
  • 열거형에 쉽게 액세스할 수 있습니다.
  • 열거형은 복잡한 유형일 수 있습니다.
  • getByValue를 많이 사용하는 경우 Enum 클래스에는 연관 캐싱이 있습니다.

몇 가지 단점:

  • 열거 형에 대한 참조를 유지하면서 일부 지저분한 메모리 관리가 진행 중입니다.
  • 여전히 유형 안전 없음

Chris

객체 리터럴 생성:

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

hvdd

당신이 사용하는 경우 백본을 , 당신은 완전한 열거 기능을 얻을 무료 사용 (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()

Yaroslav

당신의 대답은 너무 복잡합니다

 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

Xeltor

Andre 'Fi'의 솔루션을 수정했습니다.

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

시험:

 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

David Miró

Java의 열거형을 모델로 한 접근 방식을 생각해 냈습니다. 이들은 유형 안전하므로 instanceof 검사도 수행할 수 있습니다.

다음과 같이 열거형을 정의할 수 있습니다.

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

Days now는 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 } })();

Vivin Paliath

어떤 답변도 만족스럽지 않아 Yet Another Enum (YEA!) 을 만들었습니다.

이 구현:

  • 최신 JS 사용
  • 열거형을 쉽게 만들려면 이 하나의 클래스만 선언하면 됩니다.
  • colors.RED ), 문자열( colors["RED"] ) 및 색인( colors[0] )에 의한 매핑이 있지만 문자열을 배열로 전달하기만 하면 됩니다.
  • 동등한 toString()valueOf() 함수를 각 열거형 객체에 바인딩합니다(이것이 어떻게든 원하지 않으면 간단히 제거할 수 있습니다. JS의 경우 약간의 오버헤드가 있음)
  • 이름 문자열에 의한 선택적 전역 명명/저장이 있습니다.
  • enum 객체는 한 번 생성되면 수정할 수 없도록 고정됩니다.

영감을 준 Andre 'Fi'의 답변 에 특별히 감사드립니다.


코드:

 class Enums { static create({ name = undefined, items = [] }) { let newEnum = {}; newEnum.length = items.length; newEnum.items = items; for (let itemIndex in items) { //Map by name. newEnum[items[itemIndex]] = parseInt(itemIndex, 10); //Map by index. newEnum[parseInt(itemIndex, 10)] = items[itemIndex]; } newEnum.toString = Enums.enumToString.bind(newEnum); newEnum.valueOf = newEnum.toString; //Optional naming and global registration. if (name != undefined) { newEnum.name = name; Enums[name] = newEnum; } //Prevent modification of the enum object. Object.freeze(newEnum); return newEnum; } static enumToString() { return "Enum " + (this.name != undefined ? this.name + " " : "") + "[" + this.items.toString() + "]"; } }

용법:

 let colors = Enums.create({ name: "COLORS", items: [ "RED", "GREEN", "BLUE", "PORPLE" ] }); //Global access, if named. Enums.COLORS; colors.items; //Array(4) [ "RED", "GREEN", "BLUE", "PORPLE" ] colors.length; //4 colors.RED; //0 colors.GREEN; //1 colors.BLUE; //2 colors.PORPLE; //3 colors[0]; //"RED" colors[1]; //"GREEN" colors[2]; //"BLUE" colors[3]; //"PORPLE" colors.toString(); //"Enum COLORS [RED,GREEN,BLUE,PORPLE]" //Enum frozen, makes it a real enum. colors.RED = 9001; colors.RED; //0

Andrew

IE8은 freeze() 메서드를 지원하지 않습니다.
출처: 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 }

Manohar Reddy Poreddy

var ColorEnum = { red: {}, green: {}, blue: {} }

이런 식으로 다른 열거형 값에 중복 숫자를 할당하지 않도록 할 필요가 없습니다. 새 개체가 인스턴스화되고 모든 열거형 값에 할당됩니다.


Shivanshu Goyal

가장 간단한 솔루션:

창조하다

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

가치 얻기

 console.log(Status.Ready) // 1

키 가져오기

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

Ilya Gazman

es7 방법, (반복자, 정지), 사용법:

 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'

암호:

 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(', ') } }

Joseph Merdrignac

이것은 유용할 수 있습니다:

 const [CATS, DOGS, BIRDS] = ENUM();

구현은 간단하고 효율적입니다.

 function * ENUM(count=1) { while(true) yield count++ }

생성기는 얼마나 많은 상수가 있는지 모른 채 필요한 정수의 정확한 시퀀스를 생성할 수 있습니다. 또한 시작할 숫자(음수일 수 있음)를 지정하는 선택적 인수를 지원할 수도 있습니다(기본값은 1 ).


Aral Roca

빠르고 간단한 방법은 다음과 같습니다.

 var Colors = function(){ return { 'WHITE':0, 'BLACK':1, 'RED':2, 'GREEN':3 } }(); console.log(Colors.WHITE) //this prints out "0"

user2254487

다음은 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


다음은 문자열을 사용하여 열거형을 만드는 lodash 믹스인입니다. 이 버전은 조금 더 복잡하지만 자동으로 번호가 매겨집니다. 이 예제에 사용된 모든 lodash 메서드는 일반 JavaScript에 해당하므로 원하는 경우 쉽게 전환할 수 있습니다.

 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

Blake Bowen

방금 NPM 패키지 gen_enum을 게시하여 Javascript에서 Enum 데이터 구조를 빠르게 생성할 수 있습니다.

 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 문자열 역직렬화, 문자열 상수 및 비트맵 생성 등을 포함한 더 많은 기능을 제공합니다. 자세한 내용은 https://www.npmjs.com/package/constjs 를 확인하세요.

에서 업그레이드하려면 gen_enumconstjs 바로 문을 변경

 var genEnum = require('gen_enum');

에게

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

Gelin Luo

O(1)에서 값과 이름을 가져올 수 있는 Enum 클래스를 만들었습니다. 또한 모든 이름과 값을 포함하는 객체 배열을 생성할 수도 있습니다.

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

값을 가져오려면(예: C#의 Enums):

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

Oooogi

비록 정적 방법 (그리고 정적 속성) (참조 ES2015에서 지원됩니다 여기 뿐만 아니라, §15.2.2.2), 호기심 당신은 함께 바벨과 아래를 사용할 수 있습니다 es2015 사전 :

 class CellState { v: string; constructor(v: string) { this.v = v; Object.freeze(this); } static EMPTY = new CellState('e'); static OCCUPIED = new CellState('o'); static HIGHLIGHTED = new CellState('h'); static values = function(): Array<CellState> { const rv = []; rv.push(CellState.EMPTY); rv.push(CellState.OCCUPIED); rv.push(CellState.HIGHLIGHTED); return rv; } } Object.freeze(CellState);

CellState 열거형 가져오기)과 Webpack을 사용하여 모듈을 가져올 때도 예상대로 작동하는 것으로 나타났습니다.

이 방법이 다른 대부분의 답변에 비해 장점은 정적 유형 검사기 (예: Flow )와 함께 사용할 수 있고 정적 유형 검사를 사용하여 개발 시 변수, 매개변수 등이 특정 CellState 다른 열거형이 아닌 "열거형"(일반 개체 또는 기호를 사용하는 경우 구별할 수 없음).

업데이트

CellState 유형의 추가 객체를 생성할 수 있다는 결함이 있습니다 CellState 있기 때문에 CellState의 정적 필드에 할당할 수는 없지만). 그래도 아래의 보다 세련된 코드는 다음과 같은 이점을 제공합니다.

  1. CellState 유형의 개체를 더 이상 만들 수 없습니다.
  2. 두 개의 열거형 인스턴스에 동일한 코드가 할당되지 않음을 보장합니다.
  3. 문자열 표현에서 열거형을 다시 가져오는 유틸리티 메서드
  4. 열거형의 모든 인스턴스를 반환하는 values 함수는 위의 수동(및 오류가 발생하기 쉬운) 방식으로 반환 값을 만들 필요가 없습니다.

     'use strict'; class Status { constructor(code, displayName = code) { if (Status.INSTANCES.has(code)) throw new Error(`duplicate code value: [${code}]`); if (!Status.canCreateMoreInstances) throw new Error(`attempt to call constructor(${code}`+ `, ${displayName}) after all static instances have been created`); this.code = code; this.displayName = displayName; Object.freeze(this); Status.INSTANCES.set(this.code, this); } toString() { return `[code: ${this.code}, displayName: ${this.displayName}]`; } static INSTANCES = new Map(); static canCreateMoreInstances = true; // the values: static ARCHIVED = new Status('Archived'); static OBSERVED = new Status('Observed'); static SCHEDULED = new Status('Scheduled'); static UNOBSERVED = new Status('Unobserved'); static UNTRIGGERED = new Status('Untriggered'); static values = function() { return Array.from(Status.INSTANCES.values()); } static fromCode(code) { if (!Status.INSTANCES.has(code)) throw new Error(`unknown code: ${code}`); else return Status.INSTANCES.get(code); } } Status.canCreateMoreInstances = false; Object.freeze(Status); exports.Status = Status;

Marcus Junius Brutus

enum 을 Javascript로 변환하는 방법은 다음과 같습니다.

 var makeEnum = function(obj) { obj[ obj['Active'] = 1 ] = 'Active'; obj[ obj['Closed'] = 2 ] = 'Closed'; obj[ obj['Deleted'] = 3 ] = 'Deleted'; }

지금:

 makeEnum( NewObj = {} ) // => {1: "Active", 2: "Closed", 3: "Deleted", Active: 1, Closed: 2, Deleted: 3}

obj[1] 'Active' 반환하는 이유가 무엇인지 혼란스러웠지만 그 다음에는 간단하다는 것을 깨달았습니다. 할당 연산자는 값을 할당한 다음 반환합니다.

 obj['foo'] = 1 // => 1

Julius

다음과 같이 할 수 있습니다.

 var Enum = (function(foo) { var EnumItem = function(item){ if(typeof item == "string"){ this.name = item; } else { this.name = item.name; } } EnumItem.prototype = new String("DEFAULT"); EnumItem.prototype.toString = function(){ return this.name; } EnumItem.prototype.equals = function(item){ if(typeof item == "string"){ return this.name == item; } else { return this == item && this.name == item.name; } } function Enum() { this.add.apply(this, arguments); Object.freeze(this); } Enum.prototype.add = function() { for (var i in arguments) { var enumItem = new EnumItem(arguments[i]); this[enumItem.name] = enumItem; } }; Enum.prototype.toList = function() { return Object.keys(this); }; foo.Enum = Enum; return Enum; })(this); var STATUS = new Enum("CLOSED","PENDING", { name : "CONFIRMED", ackd : true }); var STATE = new Enum("CLOSED","PENDING","CONFIRMED",{ name : "STARTED"},{ name : "PROCESSING"});

이 라이브러리에 정의된 대로. https://github.com/webmodule/foo/blob/master/foo.js#L217

완전한 예 https://gist.github.com/lnt/bb13a2fd63cdb8bce85fd62965a20026


LNT

출처 : http:www.stackoverflow.com/questions/287903/how-can-i-guarantee-that-my-enums-definition-doesnt-change-in-javascript

반응형