Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am trying to understand a point of confusion I have with JavaScript objects. Specifically, I am interested in finding what, if anything, causes an object reference to break.

To demonstrate the phenomenon, I have included a copy of some output from Chrome's JavaScript console. Note that I am working with arrays here, but we would expect objects to behave similarly given the subtle distinction between arrays and objects in JS. I have added comments for clarity.

  // Set x to some array literal
> x = [1, 2, 3, 4, 5]
  [1, 2, 3, 4, 5]

  // Set y to x
> y = x
  [1, 2, 3, 4, 5]

> x
  [1, 2, 3, 4, 5] // as expected

> y
  [1, 2, 3, 4, 5] // as expected

As demonstrated above, both x and y output the expected value. Now I shuffle the values of x using a function called shuffle (specified at the bottom of this question).

  // Shuffle x
> x = shuffle(x)
  [5, 1, 4, 2, 3]

> x
  [5, 1, 4, 2, 3] // x changes as expected

> y
  [5, 1, 4, 2, 3] // y changes as expected

Again, everything works as expected above. The variables x and y have maintained reference to the same object. However, when we repeat this operation, the results are strange.

  // Shuffle x
> x = shuffle(x)
  [3, 1, 5, 4, 2]

> x
  [3, 1, 5, 4, 2] // x changes as expected

> y
  [5, 1, 4, 2, 3] // y didn't change this time

Below is the shuffle function, adapted from here. Its purpose is to shuffle the contents of an array (parameter r1) and to return the first n items of the mixed array.

function shuffle(r1,n) {

  var i = r1.length, j, tempi, tempj, r2;
  r2 = r1;

  while (--i) {
    j = Math.floor(Math.random() * (i + 1));
    tempi = r2[i];
    tempj = r2[j];
    r2[i] = tempj;
    r2[j] = tempi;
  }

  return r2.slice(0,n);
}

I have since fixed the problem by rewriting my shuffle function based on this function. However, I would still like to understand what's going on. For a quick look at the code in action, I have made a jsFiddle.

Any ideas? I appreciate your time.

share|improve this question

2 Answers 2

up vote 4 down vote accepted

If you remove the .slice(0,n);, it will behave the way you expect. slice makes a new array.

So the first time you call shuffle, within your loop you modify the array x = y = r1 = r2. Then you make a copy of it on that last line and assign that to x. Now x !== y, but they contain the exact same elements. You can test that they are distinct objects after your first call to shuffle:.

The next time you call shuffle you are shuffling the copy of x you made and y is untouched.

share|improve this answer
    
Many thanks for providing the edited fiddle. –  chrisfargen Apr 28 '13 at 2:15
    
@chrisfargen You're welcome! –  Paulpro Apr 28 '13 at 2:17

.slice() makes a shallow copy of the Array, and so you're overwriting x with a new Array.

// The original was shuffled, but now `x` is a new Array
x = shuffle(x);

That's why y showed the first shuffle (because you hadn't sliced it yet), but none thereafter. The subsequent shuffle was on the overwritten x, and y still references the original.


If you wanted to truncate the original Array, just change its .length.

So instead of this:

return r2.slice(0,n);

Do this:

r2.length = n;

...though you're not passing anything to n currently.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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