最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does an enum transpile into a function? - Stack Overflow

programmeradmin10浏览0评论

Consider:

enum Colors {
    Red,
    Green,
    Blue
}

It transpiles into this:

var Colors;
(function (Colors) {
    Colors[Colors["Red"] = 0] = "Red";
    Colors[Colors["Green"] = 1] = "Green";
    Colors[Colors["Blue"] = 2] = "Blue";
})(Colors || (Colors = {}));

Most questions about this result are answered in Enums in TypeScript: what is the JavaScript code doing?.

I quote the answers:

This is an 'immediately executing function'

And further down the topic:

think they could probably just go:

var Colors;
Colors || (Colors = {});
Colors[Colors["Cyan"] = 3] = "Cyan";
// ...

and skip the closure, but maybe I’m still missing something.

So the question remains: why wrapping this in an immediately executing function?

Consider:

enum Colors {
    Red,
    Green,
    Blue
}

It transpiles into this:

var Colors;
(function (Colors) {
    Colors[Colors["Red"] = 0] = "Red";
    Colors[Colors["Green"] = 1] = "Green";
    Colors[Colors["Blue"] = 2] = "Blue";
})(Colors || (Colors = {}));

Most questions about this result are answered in Enums in TypeScript: what is the JavaScript code doing?.

I quote the answers:

This is an 'immediately executing function'

And further down the topic:

think they could probably just go:

var Colors;
Colors || (Colors = {});
Colors[Colors["Cyan"] = 3] = "Cyan";
// ...

and skip the closure, but maybe I’m still missing something.

So the question remains: why wrapping this in an immediately executing function?

Share Improve this question edited Nov 18, 2017 at 14:05 Peter Mortensen 31.6k22 gold badges110 silver badges133 bronze badges asked Nov 18, 2017 at 8:13 FlorimondFlorimond 3413 silver badges7 bronze badges 6
  • 3 There is a very detailed explanation here: basarat.gitbooks.io/typescript/content/docs/enums.html – DSCH Commented Nov 18, 2017 at 8:20
  • @DSCH Your link does not address the question of why the closure is needed. – Derek 朕會功夫 Commented Nov 18, 2017 at 8:28
  • The most probable explanation is that it's just a matter of personal preference of whoever wrote that part of the transpiler. – JJJ Commented Nov 18, 2017 at 8:30
  • My guess is that it's due to the modularity of the transpiler. It probably uses IIFEs in general to hide temporary variables, but in this case there aren't any, so the IIFE is redundant. – Barmar Commented Nov 18, 2017 at 8:33
  • seems like multiple enums with the same name are allowed .. ha. I am more curious why the values are not inlined .. I guess to preserve the information for anyone reading/debugging the JavaScript result – Slai Commented Nov 18, 2017 at 14:13
 |  Show 1 more comment

2 Answers 2

Reset to default 13

I believe TypeScript uses IIFE (aka immediately-invoked function expression) because the variable name can be minified. If you have really long enum name, e.g. MySuperAmazingStatesNeededForWhateverIWantEnum, it can be minified inside an IIFE to just one letter

// 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={}));

Without IIFE minification wouldn't be as effective

// 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";

The difference in size is huge.

That's because in TypeScript Enums are open ended.

This means that you can do something like below:

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 }

That means that you can add new members to an already defined enum. Consider this as partial class in C# or interfaces in typescript.

The IIFE is used so that any existing definition (read object) of enum of the same name can be picked up.

Also TypeScript correctly shows reports the below error if we omit = 3 part from the second enum Colors definition.

In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.

(enum member) Colors.Black = 0

Read more here: https://basarat.gitbooks.io/typescript/docs/enums.html

EDIT: Also note that there are some benefit of using IIFE.

  1. Local scope optimization: It is always beneficial to declare your variable as close as possible to your first use of that variable. JavaScript can traverse from local scope to global scope in order to lookup a variable. Thus, using a local variable can provide performance benefit.
  2. Minification: this is already mentioned in the answer by @Piotr Kocia. It means that you can also use shorter variable names for the IIFE.

    var Colors;
    (function (C) {
        C[C["Red"] = 0] = "Red";
        C[C["Green"] = 1] = "Green";
        C[C["Blue"] = 2] = "Blue";
    })(Colors || (Colors = {}));
    

    This might not look a so lucrative proposition at this point but consider when you variable name is longer.

More on the topic "Why IIFE": http://gregfranko.com/blog/i-love-my-iife/

Hope this helps.

发布评论

评论列表(0)

  1. 暂无评论