Javascript/NodeJS passing byref - javascript

I'm still learning JS. In some other languages, you can pass variables byref and then modify them elsewhere in code.
In an attempt to avoid having lots of duplicate code, I have structured a series of callbacks and parsing like so:
class MarketData {
constructor() {
//Arrays
this.OneMinuteData = [];
this.ThreeMinuteData = [];
this.initializeCandleData();
}
initializeData() {
var client = new Client();
this._initializeData(60, client, this.OneMinuteData);
this._initializeData(180, client, this.ThreeMinuteData);
}
_initializeData(granularity, client, dataStore) {
client.GetRates({ granularity: granularity }, function(err, msg, data) {
var items = data.map(item => ({
///data mapped here
}));
dataStore = dataStore.concat(items);
}
}
So essentially I have this 'private' _initializeData function with the hopes of passing in an array and having it add to the array, but since JS passes byval, I cannot achieve the desired effect (e.g. this.OneMinuteData array is not modified).
Because of this, the only way I currently know how to work around this problem is to essentially have the same function copy-pasted for each individual array, which I find incredibly sloppy. Is there a better way of doing this?

but since JS passes byval, I cannot achieve the desired effect (e.g. this.OneMinuteData array is not modified).
While JavaScript does pass by value, that value when dealing with an object (including any array) is a reference.
See the documentation for concat:
The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.
So when you say dataStore = dataStore.concat(items);, you assign a new array to the local dataStore variable and discard the old one.
Outside the function, the original array is unchanged.
The reason the array assigned to OneMinuteData is not modified is because you never modify any array.
Push the values of items into dataStore instead.
dataStore.push.apply(dataStore, items);
NB: GetRates has the signature of an asynchronous function, so make sure you don't try to inspect the modifications to OneMinuteData before they are made.

Related

Prevent pushing to array if duplicate values are present

I'm mapping an array and based on data i'm pushing Option elements into an array as follows
let make_children: any | null | undefined = [];
buyerActivityResult && buyerActivityResult.simulcastMyAccount.data.map((item: { make: {} | null | undefined; }, key: any) => {
make_children.push(
<Option key={key}>{item.make}</Option>
);
});
Following data array has several objects and these objects have an attribute called model.
buyerActivityResult.simulcastMyAccount.data
I want to prevent pusing Options to my array if the attribute model has duplicate data. It only has to push once for all similar model values.
How can i do it?
I tried something like this
buyerActivityResult && buyerActivityResult.simulcastMyAccount.data.map((item: { model: {} | null | undefined; }, key: any) => {
model_children.indexOf(item.model) === -1 && model_children.push(
<Option key={key}>{item.model}</Option>
);
});
But still duplicate values are being pushed into my array.
Its difficult to tell what you are trying to achieve but it looks like a map may not be the right tool for the job.
A map returns the same sized length array as that of the original array that you are calling map on.
If my assumptions are correct, your buyerActivityResult.simulcastMyAccount.data array has duplicate values, and you want to remove these duplicates based on the model property? One way to achieve this would be to use the lodash library for this, using the uniq function:
const uniqueResults = _.uniq(buyerActivityResult.simulcastMyAccount.data, (item) => item.model);
The Array.prototype.map() method is supposed to be used for manipulating the data contained into the array performing the operation. To manipulate data from other variables I recommend to use a for-loop block.
If item.model is an object, the function Array.prototype.indexOf() always returns -1 because it compares the memory address of the objects and does not do a deep comparison of all properties values.
The usual solution to remove duplicate data from an array is converting the Array into a Set then back to an Array. Unfortunately, this works only on primary type values (string, number, boolean, etc...) and not on objects.
Starting here, I will review your source code and do some changes and explain why I would apply those changes. First of all, assuming the make_children array does not receive new attribution later in your code, I would turn it into a constant. Because of the initialization, I think the declaration is overtyped.
const make_children: any[] = [];
Then I think you try to do too much things at the same time. It makes reading of the source code difficult for your colleagues, for you too (maybe not today but what about in few weeks...) and it make testing, debugging and improvements nearly impossible. Let's break it down in at least 2 steps. First one is transforming the data. For example remove duplicate. And the second one create the Option element base on the result of the previous operation.
const data: { make: any }[] = buyerActivityResult?.simulcastMyAccount?.data || [];
let options = data.map((item) => !!item.model); // removing items without model.
// Here the hard part, removing duplicates.
// - if the models inside your items have a property with unique value (like an ID) you can implement a function to do so yourself. Take a look at: https://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript
// - or you can use Lodash library like suggested Rezaa91 in its answer
options = _.uniq(data, (item) => item.model);
Now you only have to create the Option elements.
for (var i = 0; i < options.length; i++) {
model_children.push(<Option key={i}>{options[i].model}</Option>);
}
// OR using the Array.prototype.map method (in this case, do not declare `model_children` at the beginning)
const model_children:[] = options.map((opt:any, i:number) => <Option key={i}>{opt.model}</Option>);
Despite the lack of context of the execution of the code you provided I hope my answer will help you to find a solution and encourage you to write clearer source code (for the sake of your colleagues and your future self).
PS: I do not know anything about ReactJs. forgive me my syntax mistakes.

Loop through nested dataLayer array to return pipe delimited strings

We have a nested dataLayer variable on our booking platform. Users can make one or multiple variables are we want to pull out a string containing each of the product types contained within the array. I am hitting a error when debugging this however.
The location of the variable I would like to collect is:
dataLayer.booking.products[i].travelType
try{
var productList = {};
for(i=0;i<dataLayer.booking.products.length;i++){
productList[dataLayer.booking.products[i].travelType];
}
return productList.join('|');
}
catch(err){}
I am naive with JS so I apologies for a basic question.
M
Your code shows that you're setting a new property of the object productList, but you're not defining a value, e.g. {foo: } instead of {foo: "bar"}. It looks like what you want is an array that you can add strings to. For example:
var productList = dataLayer.booking.products.map(function(product) {
return product.travelType;
});
return productList.join('|');
Note that this is using the Array's map method as opposed to your for loop. You could also define productList as an array in a previous line, and then use the forEach method on the products Array to loop through every item, but I think this is cleaner and still legible. You can reduce the code further with ES6 syntax, but for your question it's probably better to show code that is more clearly defined.

"Sync" two JS objects in Vue.js

I have 2 JS objects, each is rendered as Tree in a webpage.
My issue is how to force a change on one of them while user applies a change to others.
My basic idea is to "bind onChange" on each objects obviously paying attention to not generate infinite loops.
In jQuery it seems almost difficult, I read something about "proxy" but I don't understand if it could help me on this topic.
I lastly thought to vue.js. I read that vue.js is very efficient syncing js and dom objects so a change between them is almost easy, maybe is possible to sync two js objects?
To be clearer, here more details:
I have something like this:
let obj1={key1:1, key2:[1,2,3]}; // defines arbitrary data obj
let obj2={};
$.extend(obj2,obj1); // defines obj2 as clone of obj1
// do "something magic" here
I would like to get the following:
obj1.key1=2; // => should automatically set obj2.key1=2; under the hood
obj2.key2.push(4); // => should automatically set obj1.key2=[1,2,3,4] under the hood
Is there any trick to bind two (identical, cloned) data objects so that any change made on one of them is reflected to the other one, as if the involved object keys "pointed" to the same data? Since objects are assigned "by reference" in javascript, this is doable if we define a third object "obj_value" and we assign it as value to the above objects as follows:
obj1.key=obj_value; // both obj1.key and obj2.key point to the same object
obj2.key=obj_value;
But I'd like something more general, directly binding one obj key to the other, in pseudo-code:
obj1.on('change',function(key,value)
{
obj2.key=value;
})
watch: {
objChangedByUser: function (value) {
this.cloneOfobjChangedByUser = Object.assign({}, value);
}
}
Or:
computed: {
cloneOfObjChangedByUser: function () {
return Object.assign({}, this.objChangedByUser);
}
}

Node.JS behaves strange

I have a variable called uids
var uids = [];
Then I write some value to it property
uids[16778923] = "3fd6335d-b0e4-4d77-b304-d30c651ed509"
But before it
if (!uids[user.id]) {
uids[user.id] = generateKey(user);
}
This thing behaves ok. If I try to get the value of it property
uids[currentUser.id]
It will give me a value of this property. If I try to call some methods like
Object.keys(uids);
It will give me, what I expected. And here the mystery comes...
uids;
RAM rest in piece. See the node eating ram
I am very confused now. What's wrong?
This is because you are creating a huge array and node will reserve memory for it - who knows what comes. I'd say that's a scenario where you would use a Map (or a plain object, but Map feels better here.
var uids = new Map();
var key = 456464564564654;
if (! uids.has(key)) {
uids.set(key, generateKey(user))
}
You are creating an empty array (length is zero), then you assign some value to an arbitrary index. This will make the array grow as big as the index and assign the value to that index. Look at this example using node.js REPL:
> var a = []
undefined
> a[5] = "something"
'something'
> a
[ , , , , , 'something' ]
> a.length
6
Instead of creating an array, you could create a Map() or an common javascript object (singleton). Javascript objects behave like Maps but only Strings can be used as keys. If you assign a Number to be key, javascript will convert it to String automatically.
Personally, I would go with objects because they perform better. Instantiating an object takes longer than instantiating a Map (and it doesn't seem like you need to create several groups of "uids"), but once done, adding new keys and retrieving values from any key in faster when using common objects. At least that's how things go in my node.js v6.7.0 on ubuntu 14.04 but you could try for yourself. And it would also make the least alteration to your code.
var uids = {} // common/ordinary empty javascript object instead of array.
if (!uids[user.id]) { // getting value from one key works the same.
uids[user.id] = generateKey(user) // assignment works the same.
}
////
uids[16778923] = "3fd6335d-b0e4-4d77-b304-d30c651ed509" // key will be "16778923".
uids[16778923] // getting value for key "16778923" can be done using 16778923 instead of "16778923".
////
uids[currentUser.id] // still returning values like this.
Object.keys(uids) // still returning an array of keys like this. but they are all Strings.

Cloning and manipulating nested object using forEach, map, or filter without modifying original object

I'm trying to get a handle on using .map, .filter to clone and modify a big nested JSON object based on a deeply nested property. With the below code, the original data and the filtered data both end up getting modified, but I'm trying to leave the original data intact. What I'm hoping to do is have the deeply nested concerns array emptied in the final filtered object for a given id, leaving the original data as the original complete data set.
var data {...};
var dataFilter = function dataBuild(data) {
var newData = data;
newData.service_requests = newData.service_requests.map((request) => {
request.concerns = request.concerns.filter((concern) => {
return concern.building_id == 2
});
return request;
});
return newData;
};
var filtered = dataFilter(data);
Here's a fiddle with what I'm trying to do with the full object in there.
http://jsbin.com/doyoqinoxo/edit?js,console
When you do:
var newData = data;
you are simply making a second reference to the same object, so:
newData.service_requests = ...
overwrites the value in data.service_requests.
It seems you want newData to be a copy of data, not a reference to the same object. There are plenty of posts here on how to copy a nested object (a so–called deep copy), e.g. What is the most efficient way to clone an object?, but please ignore the accepted answer unless you are using jQuery. Use one of the other answers, like this one.
JSIterator .map() creates the new array with the same number of elements or does not change the original array. There might be the problem with referencing if there is object inside the array as it copies the same reference, so, when you are making any changes on the property of the object it will change the original value of the element which holds the same reference.
The solution would be to copy the object, well, array.Splice() and [...array](spread Operator) would not help in this case, you can use JavaScript Utility library like Loadash or just use below mention code:
const newList = JSON.parse(JSON.stringify(orinalArr))

Categories

Resources