This is a very interesting question.
In the process of looking at the source code, there will always be something like this:
var triggerEvents = function(events, args) {
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
switch (args.length) {
caseZero: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; }};Copy the code
(Code from Backbone)
Why is “call” faster than “apply”? Here’s what happens when they’re called.
Function.prototype.apply (thisArg, argArray)
If IsCallable (Function) is false, that is, Function cannot be called, then a TypeError is raised. If argArray is null or undefined, return the result of calling the [[Call]] internal method of Function, providing thisArg and an empty array as arguments. 3. If Type (argArray) is not Object, raise TypeError. 4. Get the length of argArray. Call argArray’s [[Get]] inner method to find the length property. Assign to len. 5. Define n as ToUint32 (len). Initialize argList as an empty list. 7. Initialize index to 0. 8, loop iteration out argArray. Repeat while (index < n) a, convert the subscript to String. Initialize indexName to ToString(index).b, and define nextArg as the result of calling argArray’s [[Get]] internal method with indexName as an argument. C. Add nextArg to argList as the last element. ThisArg = thisArg, argList = thisArg, argList = thisArg, argList = thisArg, argList = thisArg
Call (thisArg [, arg1 [, arg2…]])
If IsCallable (Function) is false, that is, Function cannot be called, then a TypeError is raised. 2. Define argList as an empty list. If this method is called with more than one argument, append each argument to the last element of argList in left-to-right order starting with arg1. Return the result of calling func’s [[Call]] internal method, providing thisArg as the value and argList as the argument list.
As you can see, apply clearly has many more steps than Call. Because of the format of the arguments (arrays) defined in Apply, more work needs to be done after being called, and the given argument format needs to be changed (Step 8). There is also some checking of parameters (Step 2) that is not necessary in Call. Another important point: No matter how many parameters apply has, the loop, steps 6-8, is executed, and in Call, step 3, is executed only if necessary.
In summary, the call method is faster than Apply because the call method’s parameter format is exactly what the internal method needs.
catch me:
Zhihu: Li Jiayi