Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 815
Dave Sag Avatar asked Oct 31 '22 03:10

Dave Sag


1 Answers

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();
like image 183
dting Avatar answered Nov 09 '22 05:11

dting