call和apply
性能比较
关于它们性能上的问题我还是在看backbone的源码时知道的,先附上backbone关于它们的源码:
var triggerEvents = function(events, args) {
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
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, a1); return;
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
}
};
可以看到,传递的参数不超过3个则使用call,超过了3个则使用apply。
瞬间感觉又长姿势了,为了加深印象,我对这两货进行了性能测试。有图有真相,要不然我逼逼谁信呢?
无参数
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite();
suite.add('apply', function(){
a();
}).add('call', function(){
b();
}).on('cycle', function(event){
console.log(String(event.target));
}).on('complete', function(){
console.log('最快的是:'+this.filter('fastest').map('name'));
}).run({
async: true
});
function a(){
var obj = {name:'a'};
function say(){}
say.apply(obj);
}
function b(){
var obj = {name:'b'};
function say(){}
say.call(obj);
}
apply x 23,847,355 ops/sec ±1.02% (86 runs sampled)
call x 27,034,022 ops/sec ±0.90% (82 runs sampled)
最快的是:call
一个参数
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite();
suite.add('apply', function(){
a(1);
}).add('call', function(){
b(1);
}).on('cycle', function(event){
console.log(String(event.target));
}).on('complete', function(){
console.log('最快的是:'+this.filter('fastest').map('name'));
}).run({
async: true
});
function a(p){
var obj = {name:'a'};
function say(p){
}
say.apply(obj,arguments);
}
function b(p){
var obj = {name:'b'};
function say(p){
}
say.call(obj,p);
}
apply x 20,431,609 ops/sec ±0.72% (85 runs sampled)
call x 26,801,504 ops/sec ±0.88% (85 runs sampled)
最快的是:call
两个参数
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite();
suite.add('apply', function(){
a(1);
}).add('call', function(){
b(1);
}).on('cycle', function(event){
console.log(String(event.target));
}).on('complete', function(){
console.log('最快的是:'+this.filter('fastest').map('name'));
}).run({
async: true
});
function a(p1,p2){
var obj = {name:'a'};
function say(p1,p2){}
say.apply(obj,arguments);
}
function b(p1,p2){
var obj = {name:'b'};
function say(p1,p2){}
say.call(obj,p1,p2);
}
apply x 16,572,150 ops/sec ±1.90% (81 runs sampled)
call x 24,683,569 ops/sec ±1.13% (82 runs sampled)
最快的是:call
四个参数
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite();
suite.add('apply', function(){
a(1,2,3,4);
}).add('call', function(){
b(1,2,3,4);
}).on('cycle', function(event){
console.log(String(event.target));
}).on('complete', function(){
console.log('最快的是:'+this.filter('fastest').map('name'));
}).run({
async: true
});
function a(p1,p2,p3,p4){
var obj = {name:'a'};
function say(p1,p2,p3){}
say.apply(obj,arguments);
}
function b(p1,p2,p3,p4){
var obj = {name:'b'};
function say(p1,p2,p3,p4){}
say.call(obj,p1,p2,p3,p4);
}
apply x 16,709,388 ops/sec ±0.73% (87 runs sampled)
call x 25,625,382 ops/sec ±1.15% (84 runs sampled)
最快的是:call
最结论可以看到,call的性能是远高于apply的
,不管传的参数有几个。那为什么backbone要这么搞?参数的数量我们无法控制,如果调用call,难道我们要写无限个call吗,当然不会,一个apply就可以包含所有的参数,虽然性能上略有下降,但是书写上却要省事许多。