0
\$\begingroup\$

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?

\$\endgroup\$
2
  • \$\begingroup\$ Wouldn't it be easier to use an object that has 'r' and 'e' and all other categories as keys and an array as the value. That way you don't have to do the entire filtering, you don't have to replace the statsArray every time. And lastly you can just push the object to the correct array directly. \$\endgroup\$
    – Shilly
    Commented May 19, 2017 at 9:19
  • \$\begingroup\$ Guys if you dont know what to answer, dont answer. Look at the reply from T.J. Crowder - now THATS an answer!! Thanks to him I now know how the array / function thingy work. \$\endgroup\$ Commented May 19, 2017 at 10:44

2 Answers 2

2
\$\begingroup\$

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.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ T.J. Crowder - now THATS an answer!! Thank you so much for teaching me how arrays, functions, objects relate. Thank you for taking the time to explain this to me. I learned a LOT from your answer!! :) \$\endgroup\$ Commented May 19, 2017 at 10:47
1
\$\begingroup\$

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
}
\$\endgroup\$
2
  • \$\begingroup\$ Thanks Nico - you are right, I didnt need any return. You would have gotten the answer, but T.J. Crowder taught me how this works so I'll have to give it to him :) \$\endgroup\$ Commented May 19, 2017 at 10:45
  • 1
    \$\begingroup\$ @torbenrudgaard Fair enough ;) It seems he has put lots of effort in those ASCII drawings \$\endgroup\$
    – Nico Van Belle
    Commented May 19, 2017 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.