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'
Related
let a = 7;
a = 3;
console.log(a); // output 3
In this case, the value 7 is still inside a memory? I was reading that all primitive data types are immutable.
The value of a is kept in memory, until garbage collection eventually recycles it. What the docs mean by immutable is that you can't directly alter the primative (in this case the integer 7). You can only replace the value.
There are examples on the docs but this is another one
let a = 1;
a.toString() // a is still 1, it cannot be mutated
However, we can assign this to another variable
let a = 1;
let b = a.toString() // b is string "1" and a remains as the integer 1
Or we can replace the value
let a = 1;
a = 10; // a is 10
Short answer: no.
Immutable is about the behaviour of the value, not about what happens when it's no longer being references: you cannot change an immutable value, you have to instead reassign your variable if you want it to point to a new value.
let b = 3;
let a = b; // the variable "a" points to the primitive value 3
b = 7; // the variable "a" still points to the primitive value 3
a = 7; // and now it points to a _different_ value. 7, in this case.
This is in contrast to things like arrays or objects, which you can change as much as you like without needing to reassign:
const obj = {};
const a = obj;
obj.cat = `meow`;
console.log(a); // this will show that "a" is { cat: "meow" }
We just changed the content of the value that "a" points to, without any reassignments.
I'm trying to construct the variable name and then test if it exists using a while loop but I think I'm creating it when I test for it so keep getting 'true' and the loop goes infinite.
var1 = "value1"
var2 = "value2"
var3 = "value3"
var i = 3
Logger.log(('value'+i)==true)
var i = 4
Logger.log(('value'+i)==true)
/*
var i = 1;
while (("value"+i) != null) {
Logger.log("value"+i)
i++;
}
*/
When I build the loop I want value4 to not exist and stop the loop but it doesn't. Because I've just created it's string I suppose, so how should I be formatting the test? First question here and I have searched but the 'construction' part seems to complicate things. Thanks.
Firstly, I'll clarify a misconception,
I want value4 to not exist and stop the loop but it doesn't. Because I've just created it's string I suppose
'value'+i doesn't create a variable. It represents the string 'value3'. In JS, strings are truthy, so you logger will print true.
Now to the question, how to check if variable exists.
The cleanest way of doing this would be to use a dictionary represented by a simple js object.
let definedVariablesDictionary = {};
definedVariablesDictionary.var1 = 'value1';
let isVarialbeDefined = variable => definedVariablesDictionary[variable] !== undefined;
console.log(isVarialbeDefined('var1')); // true
console.log(isVarialbeDefined('var2')); // false
Variable names are not strings, so your attempt to construct a string that matches the name of a variable won't evaluate that string as code.
If you want to do this, you should create an object with properties that store values, like a variable would. Then you can pass a string of the property name into the object, to retrieve the value of the property.
Also, you shouldn't check to see if the value is null as null is a valid value that a variable or property could have been set to. That check wouldn't tell you explicitly if the property was defined or not, it would only tell you if the value of the property was null. Instead, checking for the existence of the property can be done by just passing the property name into the object. If it exists, then the result is "truthy" and your if statement would proceed into the true branch. If the property doesn't exist, the return value is falsy and you'd proceed into the false branch.
let myObject = {
value1:"test1",
value2:"test2",
value3:"test3"
};
for(var i = 0; i < Object.keys(myObject).length +1; i++){
// Property names can be passed as strings using bracket notation
if(myObject["value" + i]){
console.log("value" + i + " exists and has a value of: " + myObject["value" + i]);
} else {
console.log("value" + i + " is not defined");
}
}
I ran into this potential scenario that I posed to a few of my employees as a test question. I can think of a couple ways to solve this problem, but neither of them are very pretty. I was wondering what solutions might be best for this as well as any optimization tips. Here's the question:
Given some arbitrary string "mystr" in dot notation (e.g. mystr = "node1.node2.node3.node4") at any length, write a function called "expand" that will create each of these items as a new node layer in a js object. For the example above, it should output the following, given that my object name is "blah":
blah: { node1: { node2: { node3: { node4: {}}}}}
From the function call:
mystr = "node1.node2.node3.node4";
blah = {};
expand(blah,mystr);
Alternately, if easier, the function could be created to set a variable as a returned value:
mystr = "node1.node2.node3.node4";
blah = expand(mystr);
Extra credit: have an optional function parameter that will set the value of the last node. So, if I called my function "expand" and called it like so: expand(blah, mystr, "value"), the output should give the same as before but with node4 = "value" instead of {}.
In ES6 you can do it like this:
const expand = (str, defaultVal = {}) => {
return str.split('.').reduceRight((acc, currentVal) => {
return {
[currentVal]: acc
}
}, defaultVal)
}
const blah = expand('a.b.c.d', 'last value')
console.log(blah)
Here's a method that popped up in my mind. It splits the string on the dot notation, and then loops through the nodes to create objects inside of objects, using a 'shifting reference' (not sure if that's the right term though).
The object output within the function contains the full object being built throughout the function, but ref keeps a reference that shifts to deeper and deeper within output, as new sub-objects are created in the for-loop.
Finally, the last value is applied to the last given name.
function expand(str, value)
{
var items = mystr.split(".") // split on dot notation
var output = {} // prepare an empty object, to fill later
var ref = output // keep a reference of the new object
// loop through all nodes, except the last one
for(var i = 0; i < items.length - 1; i ++)
{
ref[items[i]] = {} // create a new element inside the reference
ref = ref[items[i]] // shift the reference to the newly created object
}
ref[items[items.length - 1]] = value // apply the final value
return output // return the full object
}
The object is then returned, so this notation can be used:
mystr = "node1.node2.node3.node4";
blah = expand(mystr, "lastvalue");
var obj = {a:{b:{c:"a"}}};
const path = "a.b.c".split(".");
while(path.length > 1){
obj = obj[path.shift()];
}
obj[path.shift()] = "a";
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.
I want to create an Object that contains one or more two dimensional arrays in Javascript.
I tried it the following way (in this example I only try to add one two dimensional array):
var XSIZE = 8;
var YSIZE = 8;
var obj = {
field : new Array(XSIZE),
field[0] : new Array(YSIZE),
foo : 1,
bar : 100
}
Info:
- This gives me a strange error "missing : after property id" which does not seem to make much sense
- Unfortunately I didn't find examples showing how to do this so far by using google
- If I don't add field[0] ... for creating the 2nd array it works.
- changing the XSIZE and YSIZE to numbers like new Array(8)... doesn't work.
I would really appreciate if somebody could show me how to do it or explain why I cannot do this at all and need to use some other method.
Thanks a lot!
The error "missing : after property id" is because JavaScript sees the field part of field[0] and expects a colon before the value of that field. Instead it gets an open bracket so it complains.
You can't hard code an object definition that has its dimensions set up at run time. You have to build the object at run time as well. Like this perhaps
var XSIZE = 8;
var YSIZE = 8;
var obj = {
field : new Array(),
foo : 1,
bar : 100
}
for (var i = 0; i < XSIZE; i++) {
obj.field.push(new Array(YSIZE));
}
In object literal notation, the property names must be exactly that: property names. Firstly, field[0] isn't a property name. Secondly, the properties don't exist until the after the object defined, so you can't access properties until then.
What you should do is either set the array after the object is created:
var obj = {...}
obj.field[0] = [...];
or nest the array literals:
var obj = {
field: [ [...],
...
],
...
}
You don't need to worry about setting the array size when creating the array, as it will grow when you add elements.
You can only declare properties on the object being constructed that way; not on objects in another "level".
You could use a for loop instead:
for(var i = 0; i < XSIZE; i++) {
obj.field[i] = new Array(YSIZE);
}
Note that the YSIZE is not necessary since an empty array works just fine as well ([]).
You could get the two dimensional array as your obj property, without resorting to external procedures and keep everything internal to the object. Create your empty 'field' array 1st.
var obj = {
field:[],
foo:1,
bar:100
};
Now, create an object's method to create a two dimensional array off your initial dimensionless array. You can determine the length and the number of dimensions of multi dimension array as you wish at run time:
var obj = {
field:[],
multifield:function(x,y){for (var count=0;count<x;count++) {this.field[count]=new Array(y);}},
foo:1,
bar:100
};
You can then call the obj.multifield method entering whatever dimensions you decide:
obj.multifield(10,5); //-->create a 10x5 array in this case...
console.log(obj.field.length); // 10
console.log(obj.field[0].length); // 5