Почему перечисление переводится в функцию?
Рассмотрим:
enum Colors {
Red,
Green,
Blue
}
Он преобразуется в это:
var Colors;
(function (Colors) {
Colors[Colors["Red"] = 0] = "Red";
Colors[Colors["Green"] = 1] = "Green";
Colors[Colors["Blue"] = 2] = "Blue";
})(Colors || (Colors = {}));
В большинстве вопросов об этом ответе в перечислены в TypeScript: что делает код JavaScript?.
Я цитирую ответы:
Это "немедленно выполняющая функция"
И далее по теме:
Думаю, они могли бы просто пойти:
var Colors;
Colors || (Colors = {});
Colors[Colors["Cyan"] = 3] = "Cyan";
// ...
и пропустите закрытие, но, возможно, Im все еще что-то пропустил.
Итак, остается вопрос: зачем обертывать это в немедленно выполняющейся функции?
Ответы
Ответ 1
Я полагаю, что TypeScript использует IIFE (так называемое мгновенное выражение функции), потому что имя переменной может быть уменьшено. Если у вас действительно длинное имя перечисления, например. MySuperAmazingStatesNeededForWhateverIWantEnum
, он может быть минимизирован внутри IIFE только одной буквой
// amazing_enum.js
var MySuperAmazingStatesNeededForWhateverIWantEnum;
(function MySuperAmazingStatesNeededForWhateverIWantEnum() {
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum["Red"] = 0] = "Red";
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum["Green"] = 1] = "Green";
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum["Blue"] = 2] = "Blue";
})(MySuperAmazingStatesNeededForWhateverIWantEnum || (MySuperAmazingStatesNeededForWhateverIWantEnum = {}));
// amazing_enum.min.js
var MySuperAmazingStatesNeededForWhateverIWantEnum;!function e(){e[e.t=0]="Red",e[e.u=1]="Green",e[e.m=2]="Blue"}(MySuperAmazingStatesNeededForWhateverIWantEnum||(MySuperAmazingStatesNeededForWhateverIWantEnum={}));
Без МИФИ минификация не будет столь эффективной
// amazing_enum.js
var MySuperAmazingStatesNeededForWhateverIWantEnum;
MySuperAmazingStatesNeededForWhateverIWantEnum || (MySuperAmazingStatesNeededForWhateverIWantEnum = {}),
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.Red = 0] = "Red";
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.Green = 1] = "Green";
MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.Blue = 2] = "Blue";
// amazing_enum.min.js
var MySuperAmazingStatesNeededForWhateverIWantEnum;MySuperAmazingStatesNeededForWhateverIWantEnum||(MySuperAmazingStatesNeededForWhateverIWantEnum={}),MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.t=0]="Red",MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.u=1]="Green",MySuperAmazingStatesNeededForWhateverIWantEnum[MySuperAmazingStatesNeededForWhateverIWantEnum.m=2]="Blue";
Разница в размере огромна.
Ответ 2
Это потому, что в TypeScript перечисления открыты.
Это означает, что вы можете сделать что-то вроде ниже:
enum Colors {
Red,
Green,
Blue
}
console.log(Colors); // { '0': 'Red', '1': 'Green', '2': 'Blue', Red: 0, Green: 1, Blue: 2 }
enum Colors {
Black = 3,
White
}
console.log(Colors); // { '0': 'Red', '1': 'Green', '2': 'Blue', '3': 'Black', '4': 'White', Red: 0, Green: 1, Blue: 2, Black: 3, White: 4 }
Это означает, что вы можете добавить новых членов в уже определенный enum
. Рассмотрим это как частичный класс в С# или interface
в typescript.
IIFE используется для того, чтобы любое существующее определение (прочитанный объект) enum
с тем же именем можно было поднять.
Также TypeScript корректно отображает отчеты об ошибке ниже, если мы опустим часть = 3
из второго определения enum Colors
.
В перечислении с несколькими объявлениями только одно объявление может опустить инициализатор для своего первого элемента перечисления.
(член перечисления) Colors.Black = 0
Подробнее здесь: https://basarat.gitbooks.io/typescript/docs/enums.html
РЕДАКТИРОВАТЬ: Также обратите внимание, что есть некоторые преимущества использования IIFE.
- Локальная оптимизация области: всегда полезно объявить вашу переменную как можно ближе к первому использованию этой переменной. JavaScript может перемещаться из локальной области в глобальную область, чтобы искать переменную. Таким образом, использование локальной переменной может обеспечить производительность.
-
Minification: об этом уже упоминалось в ответе @Piotr Kocia. Это означает, что вы также можете использовать более короткие имена переменных для IIFE.
var Colors;
(function (C) {
C[C["Red"] = 0] = "Red";
C[C["Green"] = 1] = "Green";
C[C["Blue"] = 2] = "Blue";
})(Colors || (Colors = {}));
Это может показаться не столь прибыльным предложением на данный момент, но подумайте, когда вы измените имя больше.
Подробнее о теме "Почему IIFE": http://gregfranko.com/blog/i-love-my-iife/
Надеюсь, что это поможет.