Почему здесь используются экспоненциальные ключи enum? - PullRequest
2 голосов
/ 14 марта 2019

Здесь вы можете найти этот код:

enum NodeFlags {
    None = 0,
    Let = 1,
    Const = 2,
    NestedNamespace = 4,
    Synthesized = 8,
    Namespace = 16,
    ExportContext = 32,
    ContainsThis = 64,

И такие числовые константы я видел и в других местах.Какова цель этого?

Я предположил, что это сделано для того, чтобы добавить некоторые новые предметы позже где-нибудь между существующими.Особенно после просмотра этого:

    ThisNodeHasError = 32768,
    JavaScriptFile = 65536,
    ThisNodeOrAnySubNodesHasError = 131072,
    HasAggregatedChildData = 262144,
    JSDoc = 1048576,
    BlockScoped = 3, // three?

Но не проще ли в этом случае иметь такие числа, как 100, 200, 300 и т. Д.с побитовыми операциями, но я совсем не уверен после того, как увидел 3.

FWIW, список заканчивается совершенно странно:

    ReachabilityCheckFlags = 384,
    ReachabilityAndEmitFlags = 1408,
    ContextFlags = 6387712,
    TypeExcludesFlags = 20480,

PS Возможно, экспоненциальный здесь не верен (так что извините и вы можете поправить меня).

Ответы [ 3 ]

3 голосов
/ 14 марта 2019

Причина в том, что это перечисление используется как перечисление flags.Эти значения могут быть объединены с использованием побитового или (|) оператора.Таким образом, вы можете иметь значение, являющееся одновременно обоими членами перечисления

let x = NodeFlags.AwaitContext  | NodeFlags.ThisNodeHasError // The node is both an await context but also has errors

. Чтобы это работало, значения не должны мешать друг другу на битовом уровне, поэтому каждое значение должно быть степенью двойки (который будет иметь только один бит, установленный в единицу в отдельной позиции для каждой мощности)

В основном каждый бит в значении является независимым флагом.Они могли бы пойти с отдельными флагами на узле, такими как isLet, isConst, isAwaitContext, isError и т. Д., Но это было бы бесполезно с точки зрения памяти и для компилятора, который складывается, поскольку существуетмного узлов.Таким образом, одно поле из 64 битов может представлять 64 флага.

Чтобы извлечь установленное значение, вы можете использовать оператор &, например, x & NodeFlags.ThisNodeHasError !== 0 будет означать, что ThisNodeHasError установлен в переменной x.

2 голосов
/ 14 марта 2019

С объединенным флагом вы можете получить типы перечисления, проверяя значения с помощью побитового И &.

Это работает в другом направлении, где вы могли бы простодобавить все флаги с помощью поразрядно ИЛИ |

const getFlags = value => Object.keys(nodeFlags).filter(k => nodeFlags[k] & value);

var nodeFlags = { None: 0, Let: 1, Const: 2, NestedNamespace: 4, Synthesized: 8, Namespace: 16, ExportContext: 32, ContainsThis: 64 },
    blockScoped = 3,
    flagsOfBlockScoped = getFlags(blockScoped);
    
console.log(flagsOfBlockScoped);
2 голосов
/ 14 марта 2019

Это все степени двойки, поэтому в двоичном коде у вас будет

None = 0b0,
Let = 0b1,
Const = 0b10,
NestedNamespace = 0b100,
Synthesized = 0b1000,
Namespace = 0b10000,

И так далее.Это позволяет комбинировать флаги, например, 111 означает Let, Const, NestedNamespace

В вашем случае ReachabilityCheckFlags = 384 равно 0b110000000 в двоичном формате, поэтому он объединяет флаги со значениями 128 (0b10000000) и 256 (0b100000000)

...