16
votes

From my understanding the attributes of a Backbone.js model are supposed to be declared as somewhat private member variables by saying

this.set({ attributeName: attributeValue })
// accessing the value
this.get('attributeName');

But when I am writing functions whitin the actual model it seems much simpler to say like this:

this.attributeName = attributeValue;
// accessing the value
this.attributeName;

Also I would assume that the latter version would be faster to process since it doesn't go through backbone.js's event management.

So I was wondering how you pros do with attributes that are primarily used internally in the model. These are the attributes that one would actually want to be a bit shielded from the outside so having them exposed like in the latter example maybe isn't right still. When I have been looking at examples for the backbone.js view which doesn't have get and set methods it seems fine to do like in the second example. So is there any nice rule of thumb when to use get/set(attribute) or this.attribute when coding within the model? Or maybe an example of a model that makes this clearer?

2
why would you want to avoid the backbone event management ? there could be views out there listening to certain attribute regardless if they are updated inside or outside the Backbone.Model ?neebz
I just thought that when I for example in my application update some model attributes every 16th millisecond it wouldn't be a good idea to fire all those events each time? Most examples that I have come across are about Todo-lists and other things that doesn't update themselves that frequently.torno
For private model data I just do this._propName, rather than putting it in the managed area of a Backbone Model object.WiredPrairie

2 Answers

55
votes

When to use model.get(property) and model.set(...)

You should use get and set to access the model's data. This means any attributes that are part of the model's serialized representation that is retrieved using fetch and persisted using save.

When to use model.attributes.property

Never.

You should always use get, and especially set, instead of accessing the model.attributes object directly, although I've seen conflicting opinions about this. I believe there is a contract between a model and it's consumers, which guarantees that the consumer can be notified of any changes to the model's data using the change event. If you modify the internal attributes object directly, events are not sent and this contract is broken. Backbone events are very fast, especially if you don't have any listeners attached to them, and it's not a point that benefits from over-optimization on your part.

Although accessing the attributes directly instead of get is quite harmless on it's own, it should be avoided so the attributes object can be considered totally, completely private.

If you absolutely need to prevent some change triggering events, you can use the silent:true option: model.set({key:val}, {silent:true}). This does break the aforementioned contract, and even Backbone's own documentation gives the following caveat:

Note that this is rarely, perhaps even never, a good idea. Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.

When to use model.property

Any properties which are not data, i.e. temporary state variables, calculated properties etc. can be attached directly to the model entity. These properties should be considered temporary and transitive: they can be recreated upon model initialization or during its lifetime, but they should not be persisted, whether public or private. A typical naming convention is to prefix private properties with the _ character as follows:

this._privateProperty = 'foo';
this.publicProperty = 'bar';
2
votes

Never is an incomplete answer.

Sometimes you want access to the collection of model attributes - whatever those attributes might be. Consider a utility method to perform calcs on attributes, format them for output, etc.

A convenient way to do this is to access model.attributes

Consider one alternative, below:

var attributesNames = ['foo', 'bar', 'baz'];
var attributes = _(attributesNames ).map(function(attr) { return model.get(attr); });

callSomeUtilityMethod(attributes);

Two problems:

  • We've introduced coupling in the "attributeNames" collection. What if that list changes?
  • We've lost the association of name/value. We could rewrite the map above, but it becomes more work.

In this scenario, it's much more convenient to do something like this:

callSomeUtilityMethod(model.attributes);