79

I need to emulate enum type in Javascript and approach seems pretty straight forward:

var MyEnum = {Left = 1; Right = 2; Top = 4; Bottom = 8} 

Now, in C# I could combine those values like this:

MyEnum left_right = MyEnum.Left | MyEnum.Right 

and then I can test if enum has certain value:

if (left_right & MyEnum.Left == MyEnum.Left) {...} 

Can I do something like that in Javascript?

2
  • Note that the object syntax is wrong for MyEnum. CMS already provided a corrected example in his answer. Commented Oct 26, 2009 at 18:49
  • Maybe useful Commented May 26, 2024 at 8:07

6 Answers 6

102

You just have to use the bitwise operators:

var myEnum = { left: 1, right: 2, top: 4, bottom: 8 } var myConfig = myEnum.left | myEnum.right; if (myConfig & myEnum.right) { // right flag is set } 

More info:

Sign up to request clarification or add additional context in comments.

Comments

68

In javascript you should be able to combine them as:

var left_right = MyEnum.Left | MyEnum.Right; 

Then testing would be exactly as it is in your example of

if ( (left_right & MyEnum.Left) == MyEnum.Left) {...} 

Comments

17

Yes, bitwise arithmetic works in Javascript. You have to be careful with it because Javascript only has the Number data type, which is implemented as a floating-point type. But, values are converted to signed 32-bit values for bitwise operations. So as long as you don't try to use more than 31 bits, you'll be fine.

1 Comment

Interesting point. So you are talking just over a hundred items in the set which is definitely out there for usecases.
7

There is my implementation in typescript:

export class FlagEnumService { constructor(private value: number = 0) { } public get() { return this.value; } public set(value: number): this { this.value = value; return this; } public has(key: number): boolean { return !!(this.value & key); } public add(key: number): this { this.value |= key; return this; } public delete(key: number): this { this.value &= ~key; return this; } public toggle(key: number): this { this.has(key) ? this.delete(key) : this.add(key); return this; } } 

And tests for clarification

import { FlagEnumService } from './flag-enum.service'; enum Test { None = 0, First = 1, Second = 2, Third = 4, Four = 8 } describe('FlagEnumService', () => { let service: FlagEnumService; beforeEach(() => service = new FlagEnumService()); it('should create with initial value', () => { service = new FlagEnumService(Test.First); expect(service.get()).toBe(Test.First); }); it('should return true if has flag', () => { service = new FlagEnumService(Test.First); expect(service.has(Test.First)).toBe(true); }); it('should return false if doesn\'t have flag', () => { service = new FlagEnumService(Test.First); expect(service.has(Test.Second)).toBe(false); }); it('should add', () => { expect(service.add(Test.First).add(Test.Second).get()).toBe(Test.First + Test.Second); }); it('should not add the same value twice', () => { expect(service.add(Test.First).add(Test.First).get()).toBe(Test.First); }); it('should remove', () => { expect( service .add(Test.First) .add(Test.Second) .delete(Test.Second) .get() ) .toBe(Test.First); }); it('should return 0 when add then remove the same value', () => { expect(service.add(Test.First).delete(Test.First).get()).toBe(0); }); it('should not remove not added values', () => { expect(service.add(Test.First).delete(Test.Second).get()).toBe(Test.First); }); }); 

Comments

6

I've tried to create an example that demonstrates a common use case where one may want to use bit mask enums to control logging verbosity. It demonstrates the us of JavaScript bit-wise operations: See it on JSFiddle

/* * Demonstration of how a Flags enum can be simulated in JavaScript and * Used to control what gets logged based on user passed value */ // A Flags Enum (sort-of) var LogLevels = { NONE: 0, INFO: 1, TRACE: 2, DEBUG: 4, WARN: 8, ERROR: 16, FATAL: 32 }; // Initialize var currLogLevel = LogLevels.NONE; // User Sets a log level var logLevel = LogLevels.WARN; // Convert the configured logLvel to a bit-masked enum value switch (logLevel) { case LogLevels.INFO: currLogLevel = LogLevels.INFO | LogLevels.TRACE | LogLevels.DEBUG | LogLevels.WARN | LogLevels.ERROR | LogLevels.FATAL; break; case LogLevels.TRACE: currLogLevel = LogLevels.TRACE | LogLevels.DEBUG | LogLevels.WARN | LogLevels.ERROR | LogLevels.FATAL; break; case LogLevels.DEBUG: currLogLevel = LogLevels.DEBUG | LogLevels.WARN | LogLevels.ERROR | LogLevels.FATAL; break; case LogLevels.WARN: currLogLevel = LogLevels.WARN | LogLevels.ERROR | LogLevels.FATAL; break; case LogLevels.ERROR: case LogLevels.FATAL: default: currLogLevel = LogLevels.ERROR | LogLevels.FATAL; } // Example: log verbosity set to WARN, so this would NOT be logged if ((currLogLevel & LogLevels.DEBUG) == LogLevels.DEBUG) { console.log("log DEBUG"); } 

Comments

4

Flag Enumerations in JavaScript

Flag enums: Values must increment by powers of 2

var SEASONS = { Spring : 1, Summer : 2, Fall : 4, Winter : 8 }; 

Cannot use 0 in a bitwise & operation to test for a flag b/c it will always result in zero. However, it can be used for logical comparisons.

Usage examples (contrived)

var getSeasonsSelected = function( seasons ) { var selected = []; // The perens are needed around the bitwise operation due to the // greater operator precedence of `===` if ( (seasons & SEASONS.Spring) === SEASONS.Spring ) selected.push('Spring'); if ( (seasons & SEASONS.Summer) === SEASONS.Summer ) selected.push('Summer'); if ( (seasons & SEASONS.Fall) === SEASONS.Fall ) selected.push('Fall'); if ( (seasons & SEASONS.Winter) === SEASONS.Winter ) selected.push('Winter'); return selected; }; var s1 = getSeasonsSelected( SEASONS.Spring | SEASONS.Fall ); console.log(s1); //=> ["Spring", "Fall"] 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.