Search code examples
javascriptarrayscoffeescriptcloneslice

Coffeescript / Javascript Why, do the objects in a cloned array seem to lose their references when passed to a method?


I am cloning an array of objects using slice() but when I pass that cloned array into another method the array's contents are losing their references and become undefined.

class Chooser
  constructor: (@order, @items) ->
    # do stuff

  choose: ->
    console.debug "Choosing", @order.size, "from", @items.slice()
    @process(@order.size, @items.slice())
    # do stuff

  process: (count, items) ->
    console.debug "count", count
    console.debug "items", items
    console.debug "@items", @items
    # do recursive stuff that includes an items.shift()

The first console.debug gives me, as expected:

Choosing 10 items from [Item, Item]

where Item and Item are exactly what I expected.

But then the next console.debug lines give me

count 10
items [undefined x 2]
@items [Item, Item]

I understand that @items.slice() creates a shallow copy of @items, and as such the objects within the array are references to the same Item objects. The Item objects obviously still exist as they are still in the original @items array.

Why, do the objects in the cloned array seem to lose their references once within the process method?

See this Working example of the problem converted to Javascript


Solution

  • See this answer for what is happening in your code:

    https://stackoverflow.com/a/24176638/635411

    As you can see the slicing is working fine:

    var MyClass = (function() {
      
      function MyClass(items) {
        this.items = items;
      }
      
      MyClass.prototype.fn1 = function() {
        console.log(this.items);
        this.fn2(this.items.slice());
      };
      
      MyClass.prototype.fn2 = function(items){
        console.log(items);
      };
      
      return MyClass;
    })();
    
    new MyClass([{id:1, name:'a'}, {id:2, name:'b'}]).fn1();

    What you are seeing is that your array is being shifted before you expanded it in the console. If you actually stringify the object you can see that it was successfully passed in.

    var MyClass = (function() {
      
      function MyClass(items) {
        this.items = items;
      }
      
      MyClass.prototype.fn1 = function() {
        console.log(this.items);
        this.fn2(this.items.slice());
      };
      
      MyClass.prototype.fn2 = function(items){
        console.log(items);
        console.log(JSON.stringify(items, null, 2));
        items.shift();
        items.shift();
      };
      
      return MyClass;
    })();
    
    new MyClass([{id:1, name:'a'}, {id:2, name:'b'}]).fn1();