1
\$\begingroup\$

I'm curious if this is the right way of going about the issue:

function sortWordsByIncorrectAnswers(array) {
    array = array.slice(0)
    var sortedArray = array.sort(function (a, b) {
        a = a.fields.false;
        b = b.fields.false;
        return a < b ? -1 : a > b ? 1 : 0;
    });
    return sortedArray
}

I want to return a new version of the array, and not change 'array' passed into the method (deep copy).

This works as I want it to, but is this the correct way of doing this? It seems off.

\$\endgroup\$
4
  • \$\begingroup\$ You are making a shallow copy, not a deep copy. That means you get a new array, but if the elements in the array are objects or arrays themselves, then they are the same objects as in the first array (a shallow copy). A deep copy is usually done with a recursive algorithm that looks at the type of each element in the array to see if it is an object that needs to be copied. \$\endgroup\$
    – jfriend00
    Commented Dec 30, 2013 at 23:45
  • \$\begingroup\$ Doesn't array.slice(0) perform a deep copy? \$\endgroup\$ Commented Dec 30, 2013 at 23:51
  • \$\begingroup\$ No. array.slice(0) makes a shallow copy. It gives you a new array with all the same elements in it. That's the definition of a shallow copy. A deep copy would have all new elements in it too and if any of the elements in the array were arrays, those arrays would be copies too. \$\endgroup\$
    – jfriend00
    Commented Dec 30, 2013 at 23:52
  • 1
    \$\begingroup\$ You can see this answer for how to make a deep copy: stackoverflow.com/a/728694/816620 \$\endgroup\$
    – jfriend00
    Commented Dec 30, 2013 at 23:58

2 Answers 2

1
\$\begingroup\$

.slice() does not actually do a deep copy, the easiest way to do a deep copy with simple objects is

array = JSON.parse( JSON.stringify( array ) )

Also, you can sort on a boolean in a simpler way:

function sortWordsByIncorrectAnswers(array)
{
  array =  JSON.parse( JSON.stringify( array || [] ) );
  return array.sort( function(a, b)
  {
    return a.fields.false - b.fields.false;
  });
}
\$\endgroup\$
0
\$\begingroup\$

First off, that's what jQuery.extend is for. Resig answered this one himself over at StackOverflow and has documentation for the deep copy.

However, you can never completely clone an object. There are corner cases where even jQuery.extend could not possibly handle. As the author of this answer suggests:

It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.

Also, to comment at @tomdemuyt's answer, I have tried that method once in cloning object. However, it falls short when the object has non-serializable objects, like Functions. I once had an array with 6-10k entries, each 4-5 deep. When I did the stringify-parse routine, memory usage of the browser rocketed.

I'd rather rethink the approach rather than resorting to deep copies or other complicated approaches. In your case, you needed to sort an array while not affecting the original array You only need a 1-level copy in that case, and slice should work just fine.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I did mention simple objects ;) \$\endgroup\$
    – konijn
    Commented Dec 31, 2013 at 4:11

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.