Problem
Inside my main function I got a lot of these.
var statsArray = [];
statsArray = pushStats(r, htmlRecp, '', statsArray);
statsArray = pushStats(e, '', htmlExpe, statsArray);
etc...
Then I got statsArray
function where I insert or update new items in the array.
function pushStats(currKey, lineRecp, lineExpe, statsArray){
var selectStats = statsArray.filter(function(obj){
return obj.key == currKey
})
if (!selectStats.length) {
statsArray.push(
{
'key' : currKey,
'receipt' : lineRecp,
'expense' : lineExpe
}
)
} else {
if (lineRecp) {
selectStats[0].receipt = lineRecp;
} else {
selectStats[0].expense = lineExpe;
}
}
return statsArray;
}
My question is this, how can I do this smarter?
statsArray = pushStats(aa, bb, cc, statsArray);
Is this the only way to do this? To send statsArray back and forth like this?
Solution
My question is this, how can I do this smarter?
statsArray = pushStats(aa, bb, cc, statsArray);
Is this the only way to do this? To send statsArray back and forth like this?
This question is the result of a misunderstanding: You’re not “passing [the array] back and forth.” Arrays are objects. Variables don’t directly contain objects, they contain a value called an object reference which says where the object is elsewhere in memory. So what you’re doing is passing that object reference into your function and returning that reference out of it. The actual array isn’t passed into and out of the function.
Since you’re not changing the value of statsArray
in your function (you’re just changing state the object it refers to contains), you don’t need to return it, and you don’t need to assign that return value. Just remove the return statsArray;
from the end of the function and
var statsArray = [];
pushStats(r, htmlRecp, '', statsArray);
pushStats(e, '', htmlExpe, statsArray);
// ...
Let’s explain why that works:
After this line
var statsArray = [];
in memory you have this:
+−−−−−−−−−−−+ statsArray−−−−−−−−−>| (Array) | +−−−−−−−−−−−+ | length: 0 | +−−−−−−−−−−−+
The variable statsArray
contains an object reference for the array, which exists elsewhere in memory. (An object reference is a bit like a memory address.)
That means that during the first call:
pushStats(r, htmlRecp, '', statsArray);
…the statsArray
parameter contains that same reference, and both the variable and the parameter refer to the same array:
+−−−−−−−−−−−+ statsArray−−−−−−−−−−−+−−−−−>| (Array) | / +−−−−−−−−−−−+ | | length: 0 | | +−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+ | | (Call Context) | | +−−−−−−−−−−−−−−−−+ | | statsArray |−−+ | ... | +−−−−−−−−−−−−−−−−+
Changes that pushStats
makes to the state of the array change the array, not the reference. So if pushStats
pushes a new entry onto the array, you get this:
+−−−−−−−−−−−+ statsArray−−−−−−−−−−−+−−−−−>| (Array) | / +−−−−−−−−−−−+ | | length: 0 | +−−−−−−−−−−+ | | 0 |−−−−−>| (Object) | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−−−−−−−−−−+ | (Call Context) | | | ... | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−+ | statsArray |−−+ | ... | +−−−−−−−−−−−−−−−−+
After the call returns, the call context is cleaned up, and you have
+−−−−−−−−−−−+ statsArray−−−−−−−−−>| (Array) | +−−−−−−−−−−−+ | length: 0 | +−−−−−−−−−−+ | 0 |−−−−−>| (Object) | +−−−−−−−−−−−+ +−−−−−−−−−−+ | ... | +−−−−−−−−−−+
The key thing here is that the array is an object, and pushStats
just changes the state of that object, via the reference you pass into it.
Side note: You can make the function a bit more efficient using Array#find
instead of Array#filter
:
function pushStats(currKey, lineRecp, lineExpe, statsArray){
var selectStats = statsArray.find(function(obj){
return obj.key == currKey
});
if (!selectStats) {
statsArray.push(
{
'key' : currKey,
'receipt' : lineRecp,
'expense' : lineExpe
}
);
} else {
if (lineRecp) {
selectStats.receipt = lineRecp;
} else {
selectStats.expense = lineExpe;
}
}
return statsArray;
}
It needs a polyfill for obsolete browsers, but it has the advantage that it doesn’t create an unnecessary array, and stops looping through statsArray
as soon as it finds the entry you want.
There is really no reason to return the passed array from the function.
You can simply code it like this;
var statsArray = [];
pushStats(r, htmlRecp, '', statsArray);
pushStats(e, '', htmlExpe, statsArray);
etc...
function pushStats(currKey, lineRecp, lineExpe, statsArray){
var selectStats = statsArray.filter(function(obj){
return obj.key == currKey
})
if (!selectStats.length) {
statsArray.push(
{
'key' : currKey,
'receipt' : lineRecp,
'expense' : lineExpe
}
)
} else {
if (lineRecp) {
selectStats[0].receipt = lineRecp;
} else {
selectStats[0].expense = lineExpe;
}
}
// --> No more return
}