0

I am using Backbone.js, and in an overriden collection's add method I'm trying to copy an array with slice, the following way :

var modelsBefore = this.models.slice(0);
console.log('COPIED', modelsBefore, this.models);

But copy doesn't seem to work, here's what my (chromium) log shows :

COPIED [] [child]

Any idea what could cause this ?

EDIT :

Here's a jsfiddle that reproduces the problem: http://jsfiddle.net/hYDbw/5/

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
sebpiq
  • 7,540
  • 9
  • 52
  • 69
  • Why don't you store array in another variable ? – Sarfraz Feb 22 '12 at 11:44
  • why you haven't set any argument in `slice()` – xkeshav Feb 22 '12 at 11:44
  • @Sarfraz: That's what he's trying to do... – Lightness Races in Orbit Feb 22 '12 at 11:44
  • @Sarfraz: If he just assigns it to another variable, both point to the same array. – ThiefMaster Feb 22 '12 at 11:45
  • @ThiefMaster: Ah all right, true. – Sarfraz Feb 22 '12 at 11:46
  • What is the output of `[1, 2, 3].slice()` in the Chrome Developer Tools console (use `Ctrl-Shift-J` on any page to bring up one)? – Alexander Pavlov Feb 22 '12 at 11:46
  • 1
    Arguments are **not** optional (even if your particular implementation happens to work otherwise, in its current version and configuration, on the current date and in your present location). Follow the documented API, not pure chance – Lightness Races in Orbit Feb 22 '12 at 11:51
  • like Lightness Races in Orbit say below they are not optional just because it still works. what if only standard is all of a sudden supported... – Asken Feb 22 '12 at 11:53
  • Ok thanks, but that's another topic ... – sebpiq Feb 22 '12 at 11:57
  • I think the problem here is actually one of `console.log`'s asynchronicity. Did you try with `alert`? – Lightness Races in Orbit Feb 22 '12 at 15:08
  • @LightnessRacesinOrbit : Well done, I've just found the answer also : http://jsfiddle.net/sebpiq/hYDbw/14/ console : I hate you. You can post an answer, I'll accept it. – sebpiq Feb 22 '12 at 15:24
  • @sebpiq: Hopefully this is a lesson in posting an _actual_ testcase. What a waste of time this all was! – Lightness Races in Orbit Feb 22 '12 at 15:27
  • @LightnessRacesinOrbit : if I was your mother I'd wash your mouth with soap to teach you being more polite ... but I'll accept the answer anyways, because I'm a nice guy, and because it's well detailed – sebpiq Feb 22 '12 at 15:43
  • @sebpiq: I've been very polite. That everybody here wasted the first three hours is not being rude, but a fact: we did not have the real testcase, so we could not even see the real problem, let alone solve it. You're welcome for the free help and my considerable time. Perhaps next time I'll bill you for those three hours at my typical rate.... :) – Lightness Races in Orbit Feb 22 '12 at 15:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/8078/discussion-between-sebpiq-and-lightness-races-in-orbit) – sebpiq Feb 22 '12 at 15:57

4 Answers4

3

The first argument to slice is not optional:

array.slice(begin[, end])

So:

this.models.slice(0);
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

Slice requires start parameter

Asken
  • 7,679
  • 10
  • 45
  • 77
  • can you make a jsfiddle so we can test? – Asken Feb 22 '12 at 11:51
  • thing is ... I am using backbone.js, but I'll try. – sebpiq Feb 22 '12 at 11:55
  • console.log(JSON.stringify(this.models)) and use that in jsfiddle? – Asken Feb 22 '12 at 12:02
  • here it is http://jsfiddle.net/sebpiq/hYDbw/ ... I am guessing it's some kind of side effect because of backbone, but I don't even see how that could happen !!?? – sebpiq Feb 22 '12 at 12:10
  • This jsfiddle still does not reveal how `this.models` is initialized/assigned and what prototype it has. Try to come up with a minimal test case, without any extraneous code. Can you reproduce this without Backbone? Try this as a last resort: `var modelsBefore = Array.prototype.slice.call(this.models, 0);` – Alexander Pavlov Feb 22 '12 at 13:30
1

This isn't a case of the copy failing; it's a case of the copied array going out of scope before console.log actually outputs it, because console.log works asynchronously on some browsers (such as Chrome), and arrays are passed around by reference.

For example:

function foo() {
   var x = [];
   console.log(x);
   x = [1,2,3];
}

foo();

Under some conditions, you'll see [1,2,3] output rather than the [] that you'd expect.

In your scenario, I'm not entirely sure what's going on, but I suspect modelsBefore has been re-used and emptied for the next invocation of code at that scope.

If you stringify early, though, you can get around it:

function foo() {
   var x = [];
   console.log(JSON.stringify(x));
   x = [1,2,3];
}

foo();

Stringification is a synchronous process, so you're guaranteed to see [] there.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

The Collection.models in Backbone is not an Array, it is an Object. Do not expect .slice() to work correctly with it. Look for another implementation that can do what you are expecting from .slice().

PeterK
  • 51
  • 6