How typescript implements enumerations? - javascript

I was wondering about how typescript would compile an enumeration into a javascript code. So I implemented the following example:
enum Contagens {
UM,
DOIS,
TRES
}
And it was compiled into this:
"use strict";
var Contagens;
(function (Contagens) {
Contagens[Contagens["UM"] = 0] = "UM";
Contagens[Contagens["DOIS"] = 1] = "DOIS";
Contagens[Contagens["TRES"] = 2] = "TRES";
})(Contagens || (Contagens = {}));
But, I don't understand how it works... someone could explain this code to me?

The variable var Contagens; This creates the variable that will hold a reference to the enum.
The argument Contagens || (Contagens = {}) the enum is used if it already exists, and will be set to an empty object, if it doesn't. This allows enums to be extended:
enum Contagens {
UM,
DOIS,
TRES
}
enum Contagens {
CATRE = 4
}
The function function (Contagens) { takes an argument Contagens that is the value from step #2. In this function it will create the entries on the enum object. It has the same name as the outer variable Contagens, so it shadows that variable. But it's the same value, so that doesn't matter much.
The assignment.
Contagens[Contagens["UM"] = 0] = "UM";
The result of an assignment is the value being assigned.* So Contagens["UM"] = 0 does two things. It sets the key "UM" to the value 0, and it returns 0.
That returned 0 is used then in the a second assignment:
Contagens[0] = "UM";
Now the "UM" property has been assigned 0 and the 0 property has been assigned to "UM". The enum now looks like this:
{ UM: 0, "0": "UM" }
This allows you to lookup a value in an enum by its name, or get its name from its value.
Contagens.UM // 0
Contagens[0] // "UM"
Which is handy!
* The result of an assignment when delcaring a variable is undefined, but assigning a property of an object or assigning to an existing variable will return the assigned value. JS is quirky like that.

Related

javascript initialize each value in the object with a default value

I have the following code to count the number of links in a page:
let temp = {}
for (const page of pages) {
let count = temp[page.outgoingLinks.length];
if (!count) {
count = 0;
}
count++;
temp[page.outgoingLinks.length]=count;
}
Sorry for variable names like temp as I am trying show some code which would help you understand what I am trying to do. Here, I would like to avoid the need for the if check that initializes the value.
In this example, the default value is an integer. But I would like to store even an Array there, something like defaultdict in python. Any ideas on how I can do it in JS?
There is nothing like Python's defaultdict in JavaScript, however you can have a default value when accessing the property by using the nullish-coalescing operator:
let count = temp[page.outgoingLinks.length] ?? 0;
To avoid the need for the if check that initializes the value
for (const page of pages) {
temp[page.outgoingLinks.length] = temp[page.outgoingLinks.length] ? temp[page.outgoingLinks.length]++ : 0;
}
here you can direclty use ternary operator to do so.
As you want multiple default values, you could create an object that contains the default values. This object can be defined in a helper function that takes an argument which specifies the type of default value you want and returns a function that can be called with the value.
If that value is undefined or null, this function returns the required type of default value.
function getInitializer(typeOfDefault) {
const defaults = {
arr: [0, 0, 0],
num: 0,
emptyString: ''
};
return (value) => value ?? defaults[typeOfDefault];
}
// default number
const initialize = getInitializer('num');
const a = initialize(0);
console.log(a);
// default array
const initialize2 = getInitializer('arr');
const b = initialize2(null);
console.log(b);

chineseFood[array[0]] = array[array.length-1];

I don't understand the purpose of this = sign on the sixth line in the code block below. I understand how the argument grabs each index number of the array, I just don't understand why chineseFood[array[0]] = array[array.length-1]; In other words, I don't get the purpose of the equal sign as if it were almost comparing each other to be stored in the empty object that is stored in the variable chineseFood. Could someone please clarify? It would be much appreciated.
function transformFirstAndLast(array) {
var chineseFood = {};
//takes 1st element (at index 0) and sets it to the last element (nth index): array(length-1)
chineseFood[array[0]] = array[array.length - 1];
return chineseFood;
}
console.log( transformFirstAndLast(['Orange', 'Lemon', 'Pork', 'Chicken']) );
Output Below
{Orange: "Chicken"}
The equals sign is not comparison, it is assignment. chineseFood is an object, which means that it can be treated like a dictionary, and its properties can be accessed using the [] operator instead of the . operator:
myObj = {
foo: "bar"
};
console.log(myObj["foo"]); // bar
console.log(myObj.foo); // bar
Likewise, you can also assign properties this way:
myObj = {};
myObj["foo"] = 3;
console.log(myObj["foo"]); // 3
console.log(myObj.foo); // 3
This is what your code is doing. It is retrieving the value of array[array.length-1], which is "Chicken". Then it is assigning this value to the property of chineseFood that has the name represented by array[0], which happens to be "Orange". Thus, the property named Orange on chineseFood is set to array[array.length - 1], which is why chineseFood evaluates to {Orange: "Chicken"}.
This method of accessing properties is especially useful when you don't know the name of the property you will be changing in advance, as is the case with this code, or when you want to create properties that have names that would otherwise be illegal:
myObj = {
".you can't usually use with spaces or start w/ periods": false
};
myObj[".you can't usually use with spaces or start w/ periods"] = true;
console.log(myObj[".you can't usually use with spaces or start w/ periods"]);
// there is no way to read this property the normal way
Basically what is does is:
your object is :
var obj = {Orange: "Chicken"};
And Your array is :
var arr = ['Orange','Lemon','Pork','Chicken']
What this line says is pick first element of the array and check for this prop in object and change its value to last element of array, here:
arr[0] = "orange";
So this line :
obj[arr[0]] can be seen as obj['orange'].
After that you change its value:
Obj[arr[0]] = arr[arr.length-1] which can be written as obj['orange'] = 'chicken'

ES6 destructuring object assignment function parameter default value

Hi I was going through examples of object destructuring use in passing function parameters here Object Destructuring Demo
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = **{}**) {
console.log(size, cords, radius);
// do some chart drawing
}
// In Firefox, default values for destructuring assignments are not yet
implemented (as described below).
// The workaround is to write the parameters in the following way:
// ({size: size = 'big', cords: cords = { x: 0, y: 0 }, radius: radius =
25} = **{}**)
drawES6Chart({
cords: { x: 18, y: 30 },
radius: 30
});
Can anybody let me know what is reason of using empty object assignment at the end of function parameter which I have marked in bold(embedded in double stars) above?
If you use it, and call the function with no parameters, it works:
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) {
console.log(size, cords, radius);
// do some chart drawing
}
drawES6Chart();
if not, an error is thrown:
TypeError: can't convert undefined to object
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25}) {
console.log(size, cords, radius);
// do some chart drawing
}
drawES6Chart();
The destructuring with defaults only does its thing when you pass an object which doesn't have the respective properties. The = {} default for the whole parameter allows to not pass an (empty) object at all.
It makes drawES6Chart() equivalent to drawES6Chart({}).
You have an object with your default values, but that object is an argument too, so it needs an empty object as a default value for the first argument, which is the object with the filled in values.
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) {
}
That, in pseudo code, would be:
function drawES6Chart({**first argument**} = {**default value for first argument**}) {
}
Here is a (much longer than I originally intended) description of the phenomenon
you are observing from a more rigorous point of view. Why more rigorous? I
wanted to investigate this question because I wasn't sure if there was some
special rule regarding function default arguments, or if there was something
fundamental about destructuring that I didn't understand. Turns out, it was the
latter.
I'll describe my findings using pseudo-grammar that somewhat mirrors what you'll
see in ECMA-262. That is my only reference.
Key Points:
There are the Destructuring Assignments and Destructuring Binding
Patterns. The purpose of both is to introduce names and assign
values.
Destructuring Assignment:
ObjectAssignmentPattern : '{' AssignmentPropertyList '}' = AssignmentExpression
AssignmentPropertyList : AssignmentProperty [',' AssignmentProperty]
These two just state the general form of the Destructuring Assignment.
AssignmentProperty : IdentifierReference [Initializer]
This is a "default value" for a name in the LHS.
AssignmentProperty : PropertyName ':' AssignmentElement
AssignmentElement : LeftHandSideExpression [Initializer]
This lets the destructuring nest recursively, but the semantics need to be
defined.
Semantics
If you look at
DestructuringAssignmentEvaluation,
you can see who gets assigned to what. ObjectAssignmentPattern is not very
interesting, it gives the basic '{' assignments '}' structure of the LHS,
what's more interesting is 12.15.5.3,
PropertyDestructuringAssignmentEvaluation. This shows what happens when you
actually assign default values, and when you bind more deeply nested names.
AssignmentProperty : IdentifierReference [Initializer]
Step 3 is important in this algorithm, where GetV is called. In this call, it
is attempting to get the value of the name that is currently being assigned to
(LHS) from value (RHS). This can throw, and is why the following snippet
throws:
y = Object.defineProperty({},'foo',{get: () => {throw new Error("get foo");}})
{foo} = y;
The next step, step 4, just evaluates the initializer if it exists and the
value obtained from the RHS is undefined. For example:
y = Object.defineProperty({},'foo',{get: () => undefined})
{foo = 3} = y; // foo === 3
Note that this step, and the step of actually "putting" the value where it needs
to go, can both throw. The next item is more tricky, and is where confusion
most certainly arises:
AssignmentProperty : PropertyName ':' AssignmentElement
The semantics here are to kick the can down the road to
KeyedDestructuringAssignmentEvaluation,
passing the PropertyName and current value (RHS). Here's the header for its
runtime semantics:
AssignmentElement : DestructuringAssignmentTarget [Initializer]
The steps of the ensuing algorithm are somewhat familiar, with a few surprises
and indirections. Almost any step in this algorithm can throw, so it won't be
pointed out explicitly. Step 1 is another "base of recursion," saying that if
the target is not an object or array literal (e.g. just an identifier), then let
lref be that (note that it doesn't have to be an identifier, just something
that can be assigned to, e.g.
w = {}
{x:w.u = 7} = {x:3} // w == {u:3}
Then, an attempt to retrieve the "target value" value.propertyName is made,
using GetV. If this value is undefined, an attempt is made to get the
intializer value, which in step 6 is put into lref. Step 5 is the recursive
call, peeling off as many layers as necessary to achieve the base case for the
destructured assignment. Here are a few more examples that I think illustrate
the point.
More clarifying Examples:
{x={y:1}} = {} // x == {y:1}
{x:{y=1}} = {} // error, {}.x is undefined, tried to find {}.x.y
x = 'foo'
{x:{y=1}} = {x} // x == 'foo', y == 1.
// x doesn't get assigned in this destructuring assignment,
// RHS becomes {x:x} === {x:'foo'} and since 'foo'.y is
// undefined, y gets the default 1
{x:{y=1}} = {x:{y}} // error, tried to give object value {y} === {y:y} to x
// in RHS, but y is undefined at that point
y = 'foo'
{x:{y=1}} = {x:{y}} // y == 'foo', gave {y} === {y:y} === {y:'foo'} to x in RHS
{x:{y=1}} = {x:{y:2}} // y == 2, maybe what you wanted?
// exercises:
{x=1} = undefined // error
{x=1} = null // error
{x=1} = null || undefined // error
{x=1} = null | undefined // can you guess? x == 1
Function Declarations
I actually started looking into destructuring after seeing the following code in
the source for react-redux:
export function createConnect({
connectHOC = connectAdvanced,
mapStateToPropsFactories = defaultMapStateToPropsFactories,
mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
mergePropsFactories = defaultMergePropsFactories,
selectorFactory = defaultSelectorFactory
} = {}) {
So, the first place I started digging was:
14.1 Function Definitions
Here is a little "stack trace" trying to track down the relevant productions to
get me to the binding stuff.
FunctionDeclaration
FormalParameters
FormalParameterList
FormalParameter
-> 13.3.3 Destructuring Binding Patterns
BindingElement
+SingleNameBinding
++BindingIdentifier, Initializer
+BindingPattern
+ObjectBindingPattern
+BindingPropertyList
+BindingProperty
+SingleNameBinding,
+PropertyName ':' BindingElement
Semantics: Destructuring Binding vs. Destructuring Assignment
As far as I can tell, the only difference between Destructuring Binding and
Destructuring Assignment is where they can be used and how different lexical
environments are handled. Destructuring Binding outside of formal parameter
lists (and the like) require initializers, and Destructuring Binding is passed
an environment explicitly, while assignments, which by their definition implie
an initializer," get their values from the "ambience." I'd be very happy to hear
why that's wrong, but here is a quick demonstration:
var {x}; // syntax error
function noInit({x}) { return x; }
// ok
noInit() // runtime error
noInit({}) // undefined
noInit({x:4}) // 4
function binding({x:y} = {x:y}){ return y; }
function assigning(){({x:y} = {x:y}); return y}
binding() // error, cannot access y before initialization
assigning() // error, y is not defined
y = 0
binding() // still error
assigning() // 0 - now y is defined
Conclusion:
I conclude the following. The purpose of destructuring binding and assignment
is to introduce names into the current lexical environment, optionally assigning
them values. Nested destructuring is to carve out the shape of the data you
want, and you don't get the names above you for free. You can have initializers
as default values, but as soon as you use them you can't carve any deeper. If
you carve out a particular shape (a tree, in fact), what you attempt to bind to
may have undefined leaves, but the branch nodes must match what you've
described (name and shape).
Addendum
When I started this I found it helpful and interesting to see what tsc (the typescript compiler) would transpile these things into, given a target that does not support destructuring.
The following code:
function f({A,B:{BB1=7,BB2:{BBB=0}}}) {}
var z = 0;
var {x:{y=8},z} = {x:{},z};
Transpiles (tsc --target es5 --noImplicitAny false) into:
function f(_a) {
var A = _a.A,
_b = _a.B,
_c = _b.BB1,
BB1 = _c === void 0 ? 7 : _c,
_d = _b.BB2.BBB,
BBB = _d === void 0 ? 0 : _d;
}
var z = 0;
var _a = { x: {}, z: z },
_b = _a.x.y,
y = _b === void 0 ? 8 : _b,
z = _a.z;
That's a default value for the function parameter. Without using = {} JavaScript interpreter throws an error when there is no object passed to the function as it can't destructure an undefined value.

Enums in TypeScript: what is the JavaScript code doing?

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.
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 = {})
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;
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.
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:
The assignment of values to existing variables in javascript evaluates to a value (so it's an expression rather than a statement in spirit)
Object attributes (keys) can be accessed via brackets given their key
Object attributes need to be of type string or Symbol but other values will be propagated to a string if possible.
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" }
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.

How to pass variable by reference in javascript? Read data from ActiveX function which returns more than one value

I have a ActiveX object which I want to use in the browser (javascript).
There is a function I want to call. Its prototype is:
function TOPOSFiscalPrinter.DirectIO(Command: Integer; var pData: Integer;
var pString: WideString): Integer;
So, the function returns three values: result code, pData and pString;
In javascript the function does not update the variables pData and pString;
function test()
{
var d=1, s="DIRECIO:";
var code = opos.DirectIO(1024, d, s);
alert(d); alert(s);
}
Variables d and s are not updated. They must be d=0 and s="ED123456";
How to read data from function which returns more than one value in javascript?
EDIT
Apparently, Javascript always passes parameters by value, never by reference.
Is there anything I can do to pass values by reference in Javascript, or
I will have to change my design to only rely on parameters passed by
value and on return values.
Primitive types, primarily strings/numbers/booleans are passed by value for efficiency purposes. Objects such as functions, objects, arrays and the like are passed by reference. You can create an object and pass it, eg { d:1, s:'directo' } and then change the values because you're passing a reference.
There is no support for output parameter in JavaScript. Pack what you want to return in an automation object, assign values to its properties and return it, or if your return value is already occupied, create a class that has properties you can assign to in your ActiveX and add a parameter whose type is the class. In your ActiveX you can use IDispatch/Ex to get/set the properties.
Primitives like int's or float's are always passed by value for performance reasons, but you can just wrap them into e.g. a Float32Array with just one element:
a = new Float32Array([123])
a[0]; // == 123
function ChangeA(a) {
a[0] = 333;
}
ChangeA(a)
a[0]; // == 333
Make a global variable or object. Or if you're worried about other funcs accessing and changing the variables then make a singleton. The other option is to return an object. Such as like this
function TOPOSFiscalPrinter.DirectIO(Command: Integer; var pData: Integer;
var pString: WideString): Integer;
function TOPOSFiscalPrinter.DirectIO(Command, pData, pString){
....
var pObj = {
d: 0,
s: '',
code: ''
}
pObj.d = pDataAltertedValue;
pObj.s = pStringAltertedValue;
pObj.code = code;
return pObj;
}
function test()
{
var d=1, s="DIRECIO:";
var r = opos.DirectIO(1024, d, s);
code = r.code;
d = r.d;
s = r.s;
alert(d); alert(s);
}

Categories

Resources