这是一个很是有意思的问题。git
在看源码的过程当中,总会遇到这样的写法:github
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;
}
};
复制代码
( 代码来自 backbone )数组
为何call 比 apply 快?
这里就要提到他们被调用以后发生了什么。
bash
Function.prototype.apply (thisArg, argArray)app
一、若是 IsCallable(Function)为false,即 Function 不能够被调用,则抛出一个 TypeError 异常。
二、若是 argArray 为 null 或未定义,则返回调用 Function 的 [[Call]] 内部方法的结果,提供thisArg 和一个空数组做为参数。
三、若是 Type(argArray)不是 Object,则抛出 TypeError 异常。
四、获取 argArray 的长度。调用 argArray 的 [[Get]] 内部方法,找到属性 length。 赋值给 len。
五、定义 n 为 ToUint32(len)。
六、初始化 argList 为一个空列表。
七、初始化 index 为 0。
八、循环迭代取出 argArray。重复循环 while(index < n)
a、将下标转换成String类型。初始化 indexName 为 ToString(index).
b、定义 nextArg 为 使用 indexName 做为参数调用argArray的[[Get]]内部方法的结果。
c、将 nextArg 添加到 argList 中,做为最后一个元素。
d、设置 index = index+1
九、返回调用 Function 的 [[Call]] 内部方法的结果,提供 thisArg 做为该值,argList 做为参数列表。jsp
Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )性能
一、若是 IsCallable(Function)为 false,即 Function 不能够被调用,则抛出一个 TypeError 异常。
二、定义 argList 为一个空列表。
三、若是使用超过一个参数调用此方法,则以从arg1开始的从左到右的顺序将每一个参数附加为 argList 的最后一个元素
四、返回调用func的[[Call]]内部方法的结果,提供 thisArg 做为该值,argList 做为参数列表。测试
咱们能够看到,明显 apply 比 call 的步骤多不少。
因为 apply 中定义的参数格式(数组),使得被调用以后须要作更多的事,须要将给定的参数格式改变(步骤8)。 同时也有一些对参数的检查(步骤2),在 call 中倒是没必要要的。
另一个很重要的点:在 apply 中无论有多少个参数,都会执行循环,也就是步骤 6-8,在 call 中也就是对应步骤3 ,是有须要才会被执行。网站
综上,call 方法比 apply 快的缘由是 call 方法的参数格式正是内部方法所须要的格式。ui
catch me:
知乎:李佳怡