67

我需要在 Javascript 中模拟 enum 类型,并且方法看起来很简单:

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

现在,在 C# 中,我可以像这样组合这些值:

MyEnum left_right = MyEnum.Left | MyEnum.Right

然后我可以测试枚举是否具有一定的价值:

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

我可以在 Javascript 中做类似的事情吗?

4

6 回答 6

89

您只需要使用按位运算符:

var myEnum = {
  left: 1,
  right: 2,
  top: 4,
  bottom: 8
}

var myConfig = myEnum.left | myEnum.right;

if (myConfig & myEnum.right) {
  // right flag is set
}

更多信息:

于 2009-10-26T18:24:39.420 回答
64

在javascript中,您应该能够将它们组合为:

var left_right = MyEnum.Left | MyEnum.Right;

然后测试将与您的示例完全相同

if ( (left_right & MyEnum.Left) == MyEnum.Left) {...}
于 2009-10-26T17:54:08.310 回答
14

是的,按位算术在 Javascript 中有效。你必须小心它,因为 Javascript 只有Number数据类型,它是作为浮点类型实现的。但是,对于按位运算,值将转换为有符号的 32 位值。因此,只要您不尝试使用超过 31 位,就可以了。

于 2009-10-26T17:56:15.437 回答
5

我试图创建一个示例来演示一个常见用例,在该用例中,人们可能希望使用位掩码枚举来控制日志记录的详细程度。它演示了 JavaScript 逐位操作的用法:在 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");
}
于 2014-07-18T13:26:57.550 回答
3

打字稿中有我的实现:

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

并进行澄清测试

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);
    });
});
于 2020-02-10T06:37:23.817 回答
3

在 JavaScript 中标记枚举

标志枚举:值必须以 2 的幂递增

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

不能在按位&运算中使用 0 来测试标志 b/c,它总是会导致零。但是,它可以用于逻辑比较。

用法示例(人为)

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"]
于 2020-09-24T14:41:24.413 回答