Object vs Function Defaults in Backbone.js: Which Approach Minimizes Shared‑State Bugs After an Upgrade?
0 reputation · 09 Dec 2021, 23:39 UTC
0 reputation · 09 Dec 2021, 23:39 UTC
When upgrading a Backbone.js application from an older release to 1.4+, the choice of defaults for Backbone.Model can affect data integrity. A static object is shared across instances, potentially causing unintended cross‑instance mutations. A function returns a fresh object per model, avoiding shared state but adding a small overhead. The unresolved decision is whether the safety of isolated defaults outweighs the performance cost in a large‑scale application, especially when legacy code may have relied on mutable defaults that could break after an upgrade.
Key constraints:
Considering these factors, we need to evaluate the trade‑off between safety and performance. What are the measurable impacts of each approach on model instantiation time in high‑throughput scenarios? How does an upgrade from 1.3 to 1.4 affect models that originally used object defaults? Which strategy best balances data integrity and execution speed for large‑scale Backbone applications?
35775 reputation · 10 Dec 2021, 01:29 UTC
For Backbone.js Model defaults, choose the function form whenever the default value contains an array, object, or other mutable structure. Object literals are safe only for flat scalar primitives (strings, numbers, booleans, null). This is the only reliable way to prevent cross-instance shared-state bugs after an upgrade.
Backbone resolves defaults per instance. When defaults is a function, Backbone invokes it and uses the returned hash. When defaults is an object literal, Backbone copies the top-level keys into each new instance's attributes, but it does not deep-clone nested values. Two models created from the same class will share the same nested array or object reference unless the defaults function returns fresh values each call.
Do not assume that upgrading from Backbone 1.3 to 1.4 alters object-default sharing. The latent shared-reference behavior is the same. The upgrade matters only if changes in set, parse, validation, or event handling make an existing mutation visible. Inspect your bundled Backbone source to confirm how defaults is resolved in your build.
There is no universal instantiation-time number. Object defaults avoid one function call and one object allocation per model; function defaults add that cost. In most Backbone applications the overhead is negligible. If you are instantiating models at high throughput, benchmark with your real attributes, validation, and events in Node or the browser before deciding.
defaults: object literals containing [] or {}.get(), and asserts the other instance is unchanged.attributes, changed, and validation before and after the upgrade.const A = Backbone.Model.extend({
defaults: () => ({ tags: [] })
});
const a = new A();
const b = new A();
a.get('tags').push('x');
console.assert(b.get('tags').length === 0, 'shared state detected');
model.get('nested') in place; Backbone does not protect nested attributes.If your defaults function uses this or expects arguments, verify the exact _.result behavior in your Underscore/Lodash and Backbone build rather than relying on undocumented parameters.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.