Variable assigned to array not updating when array does (JS) - javascript

I am assigning a variable, proxies, equal to an array. I am trying to add items to that array at a later point in time and then access that array in other files.
The problem is, the proxyHelper.proxies value is not updating to reflect the value of proxies variable.
After modifying the array, console.log(proxies) returns the modified array, but console.log(proxyHelper.proxies) returns a blank. I need to access the proxyHelper.proxies value in other files, so you can see why this is a problem.
I use similar code elsewhere and it works fine - what am I not seeing?
var proxies = [];
proxyHelper.proxies = proxies;
proxyHelper.tester = function(win) {
electron.ipcMain.on('saveProxies', function(event, data) {
// Clear the previous proxies from list
proxies = [];
// Split proxies based on line breaks
if (data != '') {
let proxiesList = data.split('\n');
// i<= because we want to run a check to see if all proxies are added
for (let i = 0; i <= proxiesList.length; i++) {
// if the for loop hasn't ran through all proxies
if (i + 1 <= proxiesList.length) {
proxies.push(proxiesList[i]);
}
// Once it's loop through all proxies
else {
//Returns nothing
console.log(proxyHelper.proxies);
//Returns array with added items
console.log(proxies);
win.webContents.send('goodProxies', 'Saved!');
}
}
} else {
win.webContents.send('emptyProxies', 'Empty.');
}
})
}

proxies = [];
You just assigned a new array to this variable.
proxyHelper.proxies still points to the previous value, and is not affected.
You should always use a single variable, or mutate it instead of re-assigning it.

Here is what is going on in your code:
var proxies = []; // This new variable ("proxies") contains a reference to an empty array.
proxyHelper.proxies = proxies; // You assign the same reference to a property
// (named "proxies") of the "proxyHelper"
// object. The "proxies" property points
// to the same empty array as the variable above.
proxyHelper.tester = function(win) {
electron.ipcMain.on('saveProxies', function(event, data) {
proxies = []; // You assign a new reference to the global variable
// "proxies", which points to a new empty array.
// At this point the reference assigned to
// "proxyHelper.proxies" is still the original
// empty array from line 1
// ...
}
// ...
}
So when you access "proxyHelper.proxies", you are always accessing the original empty array the has never been modified...
What you should do is:
proxyHelper.proxies = []; // resets the object's property to a new empty array

Don't need proxy variable, as its changes aren't reflected to proxyHelper.proxies
Just use proxyHelper.proxies itself
Also i've cleaned up your code a little bit
There are plenty of Array methods you can use, instead of for loop
proxyHelper.proxies = []
proxyHelper.tester = function(win) {
electron.ipcMain.on('saveProxies', function(event, data) {
//Split proxies based on line breaks
if (data != '') {
let proxiesList = data.split('\n');
proxiesList.forEach(function(proxy) {
proxyHelper.proxies.push(proxy)
})
win.webContents.send('goodProxies', 'Saved!');
} else {
win.webContents.send('emptyProxies', 'Empty.');
}
})
}

Related

Cannot update local variable

Have been trying to update a local variable (which is an array) via add/remove functions. I was able to add items using add function which also updated my local array but when I tried to remove the same using my code, it still returns my old array without modifications.
However, if I try to use pop() for removing an element, everything seems to work fine.
I know that filter from my remove function is returning the modified array but it's not getting updated in my array named mainArr.
Why is the array getting updated when I replace remove functionality with mainArr.pop() but not with my code.
The code also seems to work if I replace the assignment operator from my remove function to this.mainArr = //return value from the filter.
My remove function seems to be creating a new local variable with the same name mainArr due to which it is not updating my actual mainArr. Why is it doing so? Isn't it a concept of closures that my inner function can access global variables? What am I missing here?
function test() {
let mainArr = [];
function add(func) {
mainArr.push(func);
}
function remove(num) {
mainArr = mainArr.filter(item => item !== num)
}
return {
mainArr,
add,
remove
}
}
let val = test()
val.mainArr // returns []
val.add(3)
val.add(5)
val.mainArr //returns [3, 5]
val.remove(3)
console.log(val.mainArr) // still returns [3, 5]. Why?
mainArr.push(func); mutates the array.
mainArr.filter(item => item !== num) creates a new array.
let mainArr = []; is a variable which holds your original array. Later on, you assign the filtered version to the variable.
return { mainArr, add, remove } returns the value of mainArr which (at the time) is the original array. When you later change the value of the mainArr variable, the previously returned value is still the original array (no time travel is performed!).
Create the object upfront, and then always modify properties of that object. Don't create it from variables which later have their values changed.
function test() {
function add(func) {
data.mainArr.push(func);
}
function remove(num) {
data.mainArr = data.mainArr.filter(item => item !== num)
}
const data = {
mainArr: [],
add,
remove
};
return data;
}
let val = test()
console.log(val.mainArr);
val.add(3)
val.add(5)
console.log(val.mainArr)
val.remove(3)
console.log(val.mainArr)
In modern JS, this sort of thing is generally done with a class rather than a factory though.
class Test {
constructor() {
this.mainArr = [];
}
add(value) {
this.mainArr.push(value);
}
remove(value) {
this.mainArr = this.mainArr.filter(item => item !== value)
}
}
let val = new Test()
console.log(val.mainArr);
val.add(3)
val.add(5)
console.log(val.mainArr)
val.remove(3)
console.log(val.mainArr)

Javascript: Dictionary 'key' value becomes null outside for loop

I have a function which takes a list of dictionaries [{}] as an argument. It manipulates this list of dicts by adding a new key: value pair to it where value is again a list of dictionaries. This is what the function looks like, I've added comments to explain it.
function addFilesToProjects(nonUniqueArray, lists) {
var fileList = [{}]; //this will contain the list of dictionaries that I want to add as a key to the array 'nonUniqueArray'
var filesArray = []; //this was just for testing purposes because I want to access the modified version of nonUniqueArray outside the function, which I'm not able to (it shows undefined for the new key:value pair)
for (var i = 0; i < nonUniqueArray.length; i++) {
lists.forEach(function (list) {
fileNameString = JSON.stringify(list['name']).slice(2, -2);
if (fileNameString.indexOf(nonUniqueArray[i]['title']) !== -1 && fileNameString !== nonUniqueArray[i]['title']) {
fileList.push({
'name': fileNameString
});
}
});
nonUniqueArray[i]['files'] = fileList;
//this logs out the right key:value pair to the console
console.log(nonUniqueArray[i]);
filesArray.push(nonUniqueArray[i]);
while (fileList.length > 0) {
fileList.pop();
}
}
//however, now I get everything as before except the new 'files' key has empty list [] as its value :(
console.log(nonUniqueArray);
return filesArray;
}
I have no clue why is this happening, can someone help?
You seem to think that you are adding a copy of fileList into each dictionary, but in fact are adding the same fileList into each (that is, each is a reference to the same object) so that, as #vlaz points out, when you empty out the original, you are in fact emptying out what appears in each dictionary.

Changing the value of one variable affects the value of variable which was previously assigned to it

I am getting values returned from mongodb in docs in the below code
collection.find({"Stories._id":ObjectID(storyId)}, {"Stories.$":1}, function (e, docs) {
var results = docs;
results[0].Stories = [];
}
I am assigning the value of docs to results. Then i change one array in that results to an empty array. The problem i face is, if I change the value of results, the value of docs is also getting affected!!
How can i change value of results[0] alone?
A simple JSFIDDLE link
This is because in java-script array and object are mutable by nature.
If y is an object, the following statement will not create a copy of y:
var x = y; // This will not create a copy of y.
The object x is not a copy of y. It is y. Both x and y points to the same object.
Any changes to y will also change x, because x and y are the same object.
You can use simply use of following solution:
In Jquery
results = $.extend(true,{},docs);//For deep copy
results = $.extend({},docs);//For shallow copy
results = JSON.parse(JSON.stringify(docs))
In Javascript
function clone(obj) {
var target = {};
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
target[i] = obj[i];
}
}
return target;
}
results = clone(docs);
You can change the value of 'results[0]' alone without effecting the 'docs' by using the scope concept. Try making the changes in a function rather than in an immediate line or at the same hierarchy.
I have written a sample here at Fiddle
A few months back, I was experimenting on how the concept of pass by reference works in terms of Objects in JS. We have to note that the return type of ds.find() is a json. You can read my article here
Thanks.
var docs = [1,2,3];
var results = docs;
console.log(results[0]);
var documents =[ {
'stories':'eshwar',
'place':'Hyd'
},
{
'stories':'Prasad',
'place':'Del'
},
{
'stories':'Hari',
'place':'Chennai'
}]
console.log(documents[2]); //prints {stories: "Hari", place: "Chennai"}
function ChangeAlone(documents){
var refDoc = documents;
refDoc[2] =[];
}
// the value of stories remains same in the parent object without change
console.log(documents[2].stories); //prints Hari

Javascript push Object to global array overwrites previous values?

I'm having this problem in Javascript: I want to get the longitude and latitude values from an array of Objects. This all works fine, but when I try to save it into a global array, it overwrites every previous value. The result is an array with 8 times the last pushed object.
Global array: var _coordinates = [];
function getCoordinates()
{
mark = {};
for(var key in _data)
{
if(_data.hasOwnProperty(key)){
mark["lng"] = _data[key].long;
mark["lat"] = _data[key].lat;
}
console.log(mark); // Returns different coordinates (yay)
_coordinates.push(mark);
}
console.log(_coordinates); // All coordinates are the same (meh)
}
This is my first time asking a question here. So if I forgot something, please say so.
You could try to declare and instantiate the mark object inside the for loop because right now you are modifying the same instance all the time:
function getCoordinates() {
for(var key in _data) {
var mark = {};
if(_data.hasOwnProperty(key)) {
mark["lng"] = _data[key].long;
mark["lat"] = _data[key].lat;
}
_coordinates.push(mark);
}
console.log(_coordinates);
}
The problem is that you are repeatedly modifying the same object. Your array ends up containing eight references to that one object.
To fix, move
mark = {};
into the for loop.
You are mutating the (global) variable mark in every loop. Do this instead
_coordinates.push({lng: _data[key].long, lat: data[key].lat});

Checking for duplicate Javascript objects

TL;DR version: I want to avoid adding duplicate Javascript objects to an array of similar objects, some of which might be really big. What's the best approach?
I have an application where I'm loading large amounts of JSON data into a Javascript data structure. While it's a bit more complex than this, assume that I'm loading JSON into an array of Javascript objects from a server through a series of AJAX requests, something like:
var myObjects = [];
function processObject(o) {
myObjects.push(o);
}
for (var x=0; x<1000; x++) {
$.getJSON('/new_object.json', processObject);
}
To complicate matters, the JSON:
is in an unknown schema
is of arbitrary length (probably not enormous, but could be in the 100-200 kb range)
might contain duplicates across different requests
My initial thought is to have an additional object to store a hash of each object (via JSON.stringify?) and check against it on each load, like this:
var myHashMap = {};
function processObject(o) {
var hash = JSON.stringify(o);
// is it in the hashmap?
if (!(myHashMap[hash])) {
myObjects.push(o);
// set the hashmap key for future checks
myHashMap[hash] = true;
}
// else ignore this object
}
but I'm worried about having property names in myHashMap that might be 200 kb in length. So my questions are:
Is there a better approach for this problem than the hashmap idea?
If not, is there a better way to make a hash function for a JSON object of arbitrary length and schema than JSON.stringify?
What are the possible issues with super-long property names in an object?
I'd suggest you create an MD5 hash of the JSON.stringify(o) and store that in your hashmap with a reference to your stored object as the data for the hash. And to make sure that there are no object key order differences in the JSON.stringify(), you have to create a copy of the object that orders the keys.
Then, when each new object comes in, you check it against the hash map. If you find a match in the hash map, then you compare the incoming object with the actual object that you've stored to see if they are truly duplicates (since there can be MD5 hash collisions). That way, you have a manageable hash table (with only MD5 hashes in it).
Here's code to create a canonical string representation of an object (including nested objects or objects within arrays) that handles object keys that might be in a different order if you just called JSON.stringify().
// Code to do a canonical JSON.stringify() that puts object properties
// in a consistent order
// Does not allow circular references (child containing reference to parent)
JSON.stringifyCanonical = function(obj) {
// compatible with either browser or node.js
var Set = typeof window === "object" ? window.Set : global.Set;
// poor man's Set polyfill
if (typeof Set !== "function") {
Set = function(s) {
if (s) {
this.data = s.data.slice();
} else {
this.data = [];
}
};
Set.prototype = {
add: function(item) {
this.data.push(item);
},
has: function(item) {
return this.data.indexOf(item) !== -1;
}
};
}
function orderKeys(obj, parents) {
if (typeof obj !== "object") {
throw new Error("orderKeys() expects object type");
}
var set = new Set(parents);
if (set.has(obj)) {
throw new Error("circular object in stringifyCanonical()");
}
set.add(obj);
var tempObj, item, i;
if (Array.isArray(obj)) {
// no need to re-order an array
// but need to check it for embedded objects that need to be ordered
tempObj = [];
for (i = 0; i < obj.length; i++) {
item = obj[i];
if (typeof item === "object") {
tempObj[i] = orderKeys(item, set);
} else {
tempObj[i] = item;
}
}
} else {
tempObj = {};
// get keys, sort them and build new object
Object.keys(obj).sort().forEach(function(item) {
if (typeof obj[item] === "object") {
tempObj[item] = orderKeys(obj[item], set);
} else {
tempObj[item] = obj[item];
}
});
}
return tempObj;
}
return JSON.stringify(orderKeys(obj));
}
And, the algorithm
var myHashMap = {};
function processObject(o) {
var stringifiedCandidate = JSON.stringifyCanonical(o);
var hash = CreateMD5(stringifiedCandidate);
var list = [], found = false;
// is it in the hashmap?
if (!myHashMap[hash] {
// not in the hash table, so it's a unique object
myObjects.push(o);
list.push(myObjects.length - 1); // put a reference to the object with this hash value in the list
myHashMap[hash] = list; // store the list in the hash table for future comparisons
} else {
// the hash does exist in the hash table, check for an exact object match to see if it's really a duplicate
list = myHashMap[hash]; // get the list of other object indexes with this hash value
// loop through the list
for (var i = 0; i < list.length; i++) {
if (stringifiedCandidate === JSON.stringifyCanonical(myObjects[list[i]])) {
found = true; // found an exact object match
break;
}
}
// if not found, it's not an exact duplicate, even though there was a hash match
if (!found) {
myObjects.push(o);
myHashMap[hash].push(myObjects.length - 1);
}
}
}
Test case for jsonStringifyCanonical() is here: https://jsfiddle.net/jfriend00/zfrtpqcL/
Maybe. For example if You know what kind object goes by You could write better indexing and searching system than JS objects' keys. But You could only do that with JavaScript and object keys are written in C...
Must Your hashing be lossless or not? If can than try to lose compression (MD5). I guessing You will lose some speed and gain some memory. By the way, do JSON.stringify(o) guarantees same key ordering. Because {foo: 1, bar: 2} and {bar: 2, foo: 1} is equal as objects, but not as strings.
Cost memory
One possible optimization:
Instead of using getJSON use $.get and pass "text" as dataType param. Than You can use result as Your hash and convert to object afterwards.
Actually by writing last sentence I though about another solution:
Collect all results with $.get into array
Sort it with buildin (c speed) Array.sort
Now You can easily spot and remove duplicates with one for
Again different JSON strings can make same JavaScript object.

Categories

Resources