Skip to content Skip to sidebar Skip to footer

Array.sort Doesn't Work Properly When Called Twice?

I've been playing this for a while. Why is val_a changed when I run the function to sort val b? How can I get around this? When I run the function separately they work, but when I

Solution 1:

The reason you're seeing what you're seeing is that val_a and val_b just contain references to the same array, which is also referenced from GLOBALS.items. sort changes the state of the array that all three of those variables are pointing to.

Variables contain values, not objects. When dealing with objects (including arrays), the value in the variable is a reference to the object, which actually exists elsewhere in memory. Think of that reference as a number telling the JavaScript engine where the object is elsewhere in memory. (More below.)

If you want three separate arrays (the original items, then a copy sorted by val_a, and another sorted by val_b), you want to make a shallow copy of the array before sorting it, which you can do with slice:

val_a = GLOBALS.items.slice().sort(...);

About the array being elsewhere in memory, here's a simpler example:

var a = [42]; // A variable with a reference to an array, which is// elsewhere in memory

That gives us this in memory:

                    +---------+
a<REF5512>--------->| (array) |
                    +---------+
                    | 0: 42   |
                    +---------+

(That REF5512 is just completely made up to make the point that a reference is a value. We never see the raw reference values.)

Then if we do:

var b = a;    // A copy of that same reference

That gives us this in memory:

a<REF5512>---+
             |      +---------+
             +----->| (array) |
             |      +---------+
b<REF5512>---+      | 0: 42   |
                    +---------+

If we change the state of the array (for instance, by sorting it), naturally that change is visible from either variable, as they're both referring to the same array:

b[0] = 67;

gives us

a<REF5512>---+
             |      +---------+
             +----->| (array) |
             |      +---------+
b<REF5512>---+      | 0: 67   | State of the array changed
                    +---------+

slice creates a new array with a copy of the values in the old array (just the values; the objects in your array aren't copied). So for instance:

b = a.slice();

Gives us:

                    +---------+
a<REF5512>--------->| (array) |
                    +---------+
                    | 0: 67   |
                    +---------+

                    +---------+
b<REF7341>--------->| (array) |
                    +---------+
                    | 0: 67   |
                    +---------+

Note how the reference in b is no longer the same as in a.


Side note: Your sort callbacks can be much simpler:

val_a = GLOBALS.items.sort(function (a, b) {
    returnparseFloat(a.val_a) - parseFloat(b.val_a);
});

The sort callback just has to return a value less than zero (it doesn't have to be specifically -1), greater than zero (it doesn't have to be specifically 1), or equal to zero.

Post a Comment for "Array.sort Doesn't Work Properly When Called Twice?"