I have the following code that I run in the console:
// cache the starting array - 50 elements
let asTheyWere = selDocument.fields.field;
// create the new object
let nf = {};
$j.each(selDocument.fields.field[selDocument.fields.field.length - 1], function(a, b){
nf[a] = b;
});
// make a change and add the object to the array
for(i = 0; i < 5; i++) {
nf.name = `test me ${i}`;
// console.log(nf.name) shows 'test me 0', 'test me 1' ... 'test me 4'
selDocument.fields.field.push(nf);
}
// assign the array to a new variable - now at 55 elements
let asTheyAre = selDocument.fields.field;
// check the values
console.log(asTheyWere);
console.log(asTheyAre);
I know that the console doesn't update until the code is finished, so all variables are logged with their final value. I had thought that using different variables would avoid that, but asTheyWere and asTheyAre are the same, showing 55 elements (the first should have 50), AND the values appended to the end of the array are all the same as well: they should be 'test me 0', 'test me 1', 'test me 2' and so on, but they're all 'test me 4'.
When it's all done, then running
> console.log(selDocument.fields.field)
shows 'test me 4' on all added items, so it's not just the logging.
What's going on? How can I watch the progress and see accurate values, and get the right values appended to the array?
Even though they are different variables, they are still pointing to the same value. For example:
const foo = ['hello']
const bar = foo
foo[0] = 'goodbye'
console.log(bar[0]) // prints "goodbye"!
This happens because when you assign bar = foo, you aren't actually creating a copy of foo. Instead, you're saying, this variable bar is just another name used to refer to the contents of foo.
You could try cloning the original object to compare it to the new one. If the object is comprised of simple data, you can clone it like this:
const asTheyWere = JSON.parse(JSON.stringify(selDocument.fields.field));
// Make your changes...
const asTheyAre = selDocument.fields.field;
console.log(asTheyWere);
console.log(asTheyAre);
Related
I have created variable outside to get values from inside but I only get last value in both variables.
var categoryProductid;
var PPProducttitle;
for (var key in UpdatedCategory) {
const actual = UpdatedCategory[key]
var categoryProductid = actual.id;
var PPProducttitle = actual.title;
console.log(PPProducttitle)
console.log(categoryProductid)
}
console.log(PPProducttitle)
console.log(categoryProductid)
when I do console.logs() from inside and outside of for loop I get two different values.
Any help will be appreciated thank you!!!!!
I'm going to assume that UpdatedCategory is an object (if it's an array, please see my answer here for what to use instead of for-in to loop through it).
The basic problem with that code is that you're assigning to the same variable over and over. The reason it's the same variable is that var doesn't have block scope, so the var part of var categoryProductid = actual.id; is completely ignored (and similar for var PPProducttitle = actual.title;). Instead, you're reusing the variables you declared prior to the for loop.
A variable can only hold one value, so when you assign a new value to it, it no longer holds the old value.
If you want to hold multiple values with a variable, you can assign a container to it that can hold multiple values, such as an array, an object, a Map, or a Set.
You haven't said what end result you want, but here's an example that creates two arrays and fills them with the id and title of the products from UpdatedCategory:
// Again, I'm assuming `UpdatedCategory` is an object:
const UpdatedCategory = {
a: {
id: 1,
title: "a",
},
b: {
id: 2,
title: "b",
},
c: {
id: 3,
title: "c",
},
};
// `[]` creates a new empty array.
// We can use `const` to declare these because we never change their
// value (they only ever refer to a single array), but you could use
// `let` if you preferred. Don't use `var` in new code, it's deprecated.
// Note: I've renamed these slightly to:
// 1. Stick to standard naming conventions
// * Initial capitals are used primarily for constructor functions
// * Variables referring to arrays are generally plurals
// 2. Be consistent in capitalization
const categoryProductIds = [];
const ppProductTitles = [];
for (var key in UpdatedCategory) {
// Get this property value
const actual = UpdatedCategory[key];
// Push the `id` and `title` into the relevant arrays
categoryProductIds.push(actual.id);
ppProductTitles.push(actual.title);
}
// Show the contents of the arrays
console.log(ppProductTitles);
console.log(categoryProductIds);
I was going through basics of Javscript Set.According to its defintion, A Set is a special type collection – “set of values” (without keys), where each value may occur only once.
But I see when it comes to reference types the behavior is different. Consider the following snippet:
let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
console.log("Scenario 1");
for (let user of set) {
console.log(user.name);
}
let set1 = new Set();
set1.add({ name: "John" });
set1.add({ name: "Pete" });
set1.add({ name: "Mary" });
set1.add({ name: "John" });
console.log("Scenario 2");
for (let user of set1) {
console.log(user.name);
}
I see in the scenario 1, it wont allow duplicates to be added as they are the same references. But in scenario 2 I see duplicates are being added.
Can some explain this behavior? Or Am I missing something.
How scenario 1 is different from 2?
Try doing a check of {name: 'John'} === {name: 'John'}. You would find it returns false.
Every new object has a different reference even though the contents can be same. If it gives false to you, the Set would consider it a different element too.
When you assign a variable with a Reference value, its memory location gets copied.
For example:
let john = {name: 'John'} // lets say memory: XYZ
So, every time when you do: set.add(john);, you are adding the memory location in the set. So, the Set would see you adding XYZ everytime and it won't accept duplicates.
In the second case,
When you do:
`set1.add({ name: "John" });` // You added maybe XYF
`set1.add({ name: "John" });` // You added maybe XYN
So, your Set treats them differently and adds both of them.
A Set does not look at the contents of the object itself. It only looks at the pointer to the object.
If it's not a pointer to the same physical object, then it's allowed to be added to the Set as a different physical object. In fact, you can add an object to the set and then change it's contents afterwards because the fact that it's in the set has NOTHING to do with the contents of the object, only the physical pointer to the object. If it's not the same pointer to the same object, then it can be added separately.
Here's an example:
let s = new Set();
let x1 = {name: "John"};
let x2 = {name: "John"};
console.log(x1 === x2); // false, not the same physical object
s.add(x1);
console.log(s.has(x1)); // true
console.log(s.has(x2)); // false
s.add(x2);
console.log(s.has(x2)); // true
console.log(Array.from(s)); // [{name: "John"}, {name: "John"}];
// now modify x1
x1.name = "Bob";
// the x1 object is still in the set, even though you modified it
// because being in the set has NOTHING to do with the contents of the object at all
console.log(s.has(x1)); // true
console.log(Array.from(s)); // [{name: "Bob"}, {name: "John"}];
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'
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";
I'm faced with a situation in JavaScript when I need to update an object via its pointer similar to С++ array of pointers to objects
Example code for my issue:
var foo = new Array();
var bar = function(){
this.test = 1;
foo.push(this); // push an object (or a copy of object?) but not pointer
};
var barInst = new bar(); // create new instance
// foo[0].test equals 1
barInst.test = 2;
// now barInst.test equals 2 but
// foo[0].test still equals 1 but 2 is needed
So, how can I solve this? Should I use a callback or something like this or there is an easy way to help me to avoid copying the object instead pushing the raw pointer into an array?
JS is pass-by-value, so your original assignment was this.test = the value of 1, in my example, it's this.test = the object pointed to by ptr, so when I change ptr this.test changes as well.
var foo = [],
ptr = {val: 1},
bar = function(){
this.test = ptr;
foo.push(this); // push an object (or a copy of object?) but not pointer
},
barInst = new bar(); // create new instance
// foo[0].test.val equals 1
ptr.val = 2;
// foo[0].test.val equals 2
Although if you thought that foo.push(this); was similar, it isn't. Since this is an object, the array will indeed contain "raw pointers" to objects, just like you want. You can prove this simply:
foo[0].test = 3;
// barInst.test === 3
Which shows that it is indeed a pointer to the object that was pushed onto the array
"create object method pointer"
Object.defineProperty(Object.prototype,'pointer',{
value:function(arr, val){
return eval(
"this['"+arr.join("']['")+"']"+
((val!==undefined)?("="+JSON.stringify(val)):"")
);
}
});
ex of use
var o={a:1,b:{b1:2,b2:3},c:[1,2,3]}, arr=['b','b2']
o.pointer(arr) // value 3
o.pointer(['c',0], "new_value" )