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)

The author prefers to use the Call method for event processing when the number of parameters is less than 3. The Apply method is only considered when there are too many parameters (more than three).
The reason for this is that call is faster than Apply.
There are many examples on the Internet that prove that call is faster than Apply. Take a look at the call and Apply performance comparison examples in this article, which are very comprehensive. Or you can write a few simple ones and test them out. Here is a fantastic website, Jsperf, to test JS performance.
A few simple examples:





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