Reputation:
In the snippet below from backbone, this line
(ev = events[i]).callback.call(ev.ctx);
is not clear. I would like to assume that ev = events[i]
is interpreted before ev.ctx
as the variable seems to have no other purpose except to reduce array indexing.
Assuming this is correct, is this done because array indexing is costly? I know in embedded engineering array indexing is costly when you are working with limited resources. But I thought this was not such a concern in JavaScript.
Backbone Snippet
triggerEvents = function(events, args) {
var ev,
i = -1,
l = events.length;
switch (args.length) {
case 0:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx);
}
return;
case 1:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, args[0]);
}
return;
case 2:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
}
return;
case 3:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
}
return;
default:
while (++i < l) {
(ev = events[i]).callback.apply(ev.ctx, args);
}
}
};
Upvotes: 3
Views: 154
Reputation: 30456
OK using the treehugger.js demo to generate an AST of the backbone.js approach with this simplified bit of code:
var ev, i = -1, l = 3;
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
}
Produces this AST:
[
VarDecls(
[
VarDecl("ev"),
VarDeclInit(
"i",
PrefixOp(
"-",
Num("1")
)
),
VarDeclInit(
"l",
Num("3")
)
]
),
While(
Op(
"<",
PrefixOp(
"++",
Var("i")
),
Var("l")
),
Block(
[
Call(
PropAccess(
PropAccess(
Assign(
Var("ev"),
Index(
Var("events"),
Var("i")
)
),
"callback"
),
"call"
),
[
PropAccess(
Var("ev"),
"ctx"
),
Index(
Var("args"),
Num("0")
),
Index(
Var("args"),
Num("1")
),
Index(
Var("args"),
Num("2")
)
]
)
]
)
)
]
While the implied "cleaner" approach:
var ev, i = -1, l = 3;
while (++i < l) {
ev = events[i];
ev.callback.call(ev.ctx, args[0], args[1], args[2]);
}
Produces this AST:
[
VarDecls(
[
VarDecl("ev"),
VarDeclInit(
"i",
PrefixOp(
"-",
Num("1")
)
),
VarDeclInit(
"l",
Num("3")
)
]
),
While(
Op(
"<",
PrefixOp(
"++",
Var("i")
),
Var("l")
),
Block(
[
Assign(
Var("ev"),
Index(
Var("events"),
Var("i")
)
),
Call(
PropAccess(
PropAccess(
Var("ev"),
"callback"
),
"call"
),
[
PropAccess(
Var("ev"),
"ctx"
),
Index(
Var("args"),
Num("0")
),
Index(
Var("args"),
Num("1")
),
Index(
Var("args"),
Num("2")
)
]
)
]
)
)
]
The only difference between these two is the Assign()
takes place inside the PropAccess()
while in the "cleaner" approach has it outside. They have the same number of steps. You could avoid the Assign
all together and swap it with a second Index
. I'm afraid I don't know enough about JS internals to know if this is faster. I would guess it is platform dependent.
Upvotes: 1