Backbone.js Empty Array Attribute

Be careful about trusting the console, there is often asynchronous behavior that can trip you up.

You’re expecting console.log(x) to behave like this:

  1. You call console.log(x).
  2. x is dumped to the console.
  3. Execution continues on with the statement immediately following your console.log(x) call.

But that’s not what happens, the reality is more like this:

  1. You call console.log(x).
  2. The browser grabs a reference to x, and queues up the “real” console.log call for later.
  3. Various other bits of JavaScript run (or not).
  4. Later, the console.log call from (2) gets around to dumping the current state of x into the console but this x won’t necessarily match the x as it was in (2).

In your case, you’re doing this:

console.log(this.attributes);
console.log(this.attributes.widgets);

So you have something like this at (2):

         attributes.widgets
             ^         ^
             |         |
console.log -+         |
console.log -----------+

and then something is happening in (3) which effectively does this.attributes.widgets = [...] (i.e. changes the attributes.widget reference) and so, when (4) comes around, you have this:

         attributes.widgets // the new one from (3)
             ^
             |
console.log -+
console.log -----------> widgets // the original from (1)

This leaves you seeing two different versions of widgets: the new one which received something in (3) and the original which is empty.

When you do this:

console.log(_(this.attributes).clone());
console.log(_(this.attributes.widgets).clone());

you’re grabbing copies of this.attributes and this.attributes.widgets that are attached to the console.log calls so (3) won’t interfere with your references and you see sensible results in the console.

That’s the answer to this:

It’s showing that widgets is not empty when logging this.attributes but it’s shown as empty when logging this.attributes.widgets. Does anyone know what would cause this?

As far as the underlying problem goes, you probably have a fetch call somewhere and you’re not taking its asynchronous behavior into account. The solution is probably to bind to an "add" or "reset" event.

Leave a Comment