I have started learning Backbone.js. Currently my JavaScript skills are not too good. I have started to examine the backbone.js
file and have come across a strange line of code whose purpose I can not figure out. Code sample (if you need more context, manually download backbone.js for developers and see line 80):
var Events = Backbone.Events = {
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on: function(name, callback, context) {
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
var events = this._events[name] || (this._events[name] = []);
events.push({callback: callback, context: context, ctx: context || this});
return this;
},
What does the line this._events || (this._events = {});
mean? For me, _events
looks like an inner variable, but is (this._events = {})
used for assignment or is it an or comparison? Or is ||
a completely different operation in this context?
It is a trick that uses javascripts "falsy" evaluation. It is the same as:
if (this._events) {
// do nothing, this._events is already defined
} else {
this._events = {};
}
The same goes for the line var events = this._events[name] || (this._events[name] = []);
which could be translated to
var events;
if (this._events[name]) {
events = this._events[name];
} else {
this._events[name] = [];
events = this._events[name];
}
What line “this._events || (this._events = {});” means?
The logical OR (||) executes the first expression this._events
and if falsy executes the second expression (this._events = {})
.
In essence it checks if this._events
is falsy and if so then assigns a new empty object to it.
That way no matter what this._events
will always be at least an empty object and the code following will be able to execute without issues.
It's a way to write
if (!this._events) {
this._events = {};
}
In my opinion it's bad practice to use that kind of short hand, and I think the following line
var events = this._events[name] || (this._events[name] = []);
is even worse.
Mixing assignment, of the events
with the creation of this._events[name]
is quite short, but it's also hard to read. If you don't know what you're doing you might introduce subtle errors that way. That doesn't outweigh the benefits of having it all in one line.
And in the end it will be minified anyway. Let the minifiers take care of stuffing everything in one line. No need to do it yourself.