Reputation: 1109
The following TypeScript:
enum PrimaryColors { Red, Green, Blue };
Produces the following JavaScript:
var PrimaryColors;
(function (PrimaryColors) {
PrimaryColors[PrimaryColors["Red"] = 0] = "Red";
PrimaryColors[PrimaryColors["Green"] = 1] = "Green";
PrimaryColors[PrimaryColors["Blue"] = 2] = "Blue";
})(PrimaryColors || (PrimaryColors = {}));
;
I am embarrassed to admit that I don't understand what the JavaScript is doing.
The function in parentheses is assigning string values using another assignment as the index/key. I have not seen anything like this before.
And what is the purpose of the (PrimaryColors || (PrimaryColors = {}) following the function?
If the answer is to learn JavaScript properly, I will readily accept it, provided it comes with a suggested source that clearly explains what I am seeing here.
Upvotes: 23
Views: 10215
Reputation: 301
Lots of great answers here and thank you all, but I would like to add more for simplicity and for my personal reference, and for others who have the same learning structure in breaking things down to the last bit, I will be skipping the Immediately-invoked Function Expressions (IIFE) ill image we all already know that part
now let me break it step by step
PrimaryColors = {} // right now this is an empty object
PrimaryColors[PrimaryColors["Red"]=0] = 'Red'
the most important part here is many don't know that when u set a value to an object you get a returned value
like below
pp = {}
dd = pp['red']=0
0 // as you can see here the result of the assignment is returned
//now dd is assigned this returned value
// this is the same thing going on here.
> dd
0
we are setting the returned value as the key which is 0 which the javascript hashing algorithm converts to a string and returns as a string.
I hope everyone understands.
Upvotes: 0
Reputation: 41
It is used to create an associated map (in other words an object) where you will retrieve the 'name' of the enum value by using the index as key and vice versa. In other words: PrimaryColors["Red"]
(or PrimaryColors.Red
using dot notation) will yield 0
. PrimaryColors[0]
(dot notation would be invalid here) will yield "Red"
.
Understanding the implementation is actually not that hard if we consider three concepts:
Therefore:
PrimaryColors[PrimaryColors["Red"] = 0] = "Red";
is equivalent to
const valueToBeUsedAsIndex = PrimaryColors.Red = 0; // assignment evaluates to 0, i. e. valueToBeUsedAsIndex has value 0
PrimaryColors[valueToBeUsedAsIndex] = "Red"; // PrimaryColors[0] is "Red". Technically this assignment yields a value too ("Red" in this particular case) but the value is discarded as it's not needed anymore
// at this point PrimaryColors looks like this: { Red: 0, "0": "Red" }
Upvotes: 0
Reputation: 86
I found this question because I was wondering why use an IIFE at all when you can just init the var with {}
right off. The previous answers don’t cover it, but I’ve found my answer in the TypeScript Deep Dive.
The thing is, enums can be split into multiple files. You just have to explicitly initialize the first member of second, third, etc. enums, so this:
enum Colors {
Red,
Green,
Blue
}
enum Colors {
Cyan = 3,
Magenta,
Lime
}
transpiles to this:
var Colors;
(function (Colors) {
Colors[Colors["Red"] = 0] = "Red";
Colors[Colors["Green"] = 1] = "Green";
Colors[Colors["Blue"] = 2] = "Blue";
})(Colors || (Colors = {}));
var Colors;
(function (Colors) {
Colors[Colors["Cyan"] = 3] = "Cyan";
Colors[Colors["Magenta"] = 4] = "Magenta";
Colors[Colors["Lime"] = 5] = "Lime";
})(Colors || (Colors = {}));
As you probably know, redeclaring a variable within the same scope is harmless, but reinitialization is not.
I 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.
Upvotes: 6
Reputation: 14629
Maybe this will help.
(function() {})();
This is an 'immediately executing function'. It defines a function as an expression, and then invokes it.
var x = y || y = {};
If a common pattern for initializing something to a default value. If y does not have a value, the 1st part of the or-statement is false, so it executes the 2nd part, which assigns a value to y. The value of that 2nd expression is the new value of y. So x becomes that value of y -- which is the new value if it wasn't already defined.
x[y] = z;
Objects in JS are associative arrays. In other words, string-object pairs, like IDictionary(string,object). This expression is setting the key with value y to the value of z, in the dictionary x;
x[x["a"] = 0] = "a";
So, same thing here, but with a nested expression, which is:
x["a"] = 0;
So that just sets the value of key "a". Nothing fancy. But this is also an expression, whose value is 0. So substitute that in the original expression:
x[0] = "a";
Keys need to be strings, so it's actually the same thing as:
x["0"] = "a";
Which just sets yet another key in the dictionary. Result is that these statements are true:
x["0"] === "a";
x["a"] === 0;
Upvotes: 11
Reputation:
I believe:
PrimaryColors[PrimaryColors["Red"] = 0] = "Red";
is equivalent to:
PrimaryColors[0] = "Red";
PrimaryColors["Red"] = 0;
See this reference.
The expression x = 7 is an example of the first type. This expression uses the = operator to assign the value seven to the variable x. The expression itself evaluates to seven.
For example:
console.log((x = 7));
outputs:
7
Similarly:
var x = {};
console.log((x["hi"] = 7));
Also outputs 7.
As for the second thing, PrimaryColors
is initially undefined.
var x;
console.log(x); // undefined
In a boolean context, undefined
evaluates to false
:
console.log(!undefined); // true
console.log(!!undefined); // false
Sanity check:
console.log((!undefined) === true); // true
console.log((!!undefined) === false); // true
console.log(undefined === false); // false
This is a common usage of short circuiting. Because PrimaryColors
is initially undefined (false), it will pass {}
to the function.
PrimaryColors || (PrimaryColors = {})
Upvotes: 22