Это очень интересный вопрос.
В процессе просмотра исходного кода вы всегда будете сталкиваться с таким способом написания:
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;
}
};
(код из магистрали)
Почему вызов быстрее, чем применение?
Вот что происходит после их вызова.
Function.prototype.apply (thisArg, argArray)
1. Если IsCallable(Function) имеет значение false, то есть функция не может быть вызвана, генерируется исключение TypeError.
2. Если argArray имеет значение null или не определено, вернуть результат вызова внутреннего метода [[Call]] функции, указав thisArg и пустой массив в качестве параметров.
3. Если тип (argArray) не является объектом, будет выдано исключение TypeError.
4. Получите длину массива argArray. Вызовите внутренний метод [[Get]] массива argArray, чтобы найти длину свойства. Назначен лен.
5. Определите n как ToUint32(len).
6. Инициализируйте argList пустым списком.
7. Инициализировать индекс до 0.
8. Цикл итеративно извлекает массив argArray. Повторить цикл while(index А. Преобразуйте индекс в тип String. Инициализируйте indexName в ToString (индекс).
б) Определите nextArg как результат вызова внутреннего метода [[Get]] массива argArray с indexName в качестве параметра.
в) Добавьте nextArg в список argList в качестве последнего элемента.
d, установить индекс = индекс + 1
9. Возвращает результат вызова внутреннего метода [[Call]] функции, предоставляя thisArg в качестве значения и argList в качестве списка параметров.
Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
1. Если IsCallable(Function) имеет значение false, то есть функция не может быть вызвана, будет выдано исключение TypeError.
2. Определите argList как пустой список.
3. Если этот метод вызывается с более чем одним аргументом, добавьте каждый аргумент в качестве последнего элемента argList в порядке слева направо, начиная с arg1.
4. Вернуть результат вызова внутреннего метода [[Call]] функции func, указав thisArg в качестве значения и argList в качестве списка параметров.
Мы видим, что у применения, очевидно, гораздо больше шагов, чем у вызова.
Из-за формата параметра (массива), определенного в apply, после вызова необходимо выполнить дополнительные действия, а формат данного параметра необходимо изменить (шаг 8). Также есть некоторая проверка параметров (шаг 2), которая не нужна при вызове.
Еще очень важный момент: в apply, сколько бы ни было параметров, цикл будет выполняться, то есть шаги 6-8, в call, что соответствует шагу 3, он будет выполняться только в случае необходимости.
Подводя итог, можно сказать, что причина, по которой метод вызова работает быстрее, чем метод apply, заключается в том, что формат параметра метода вызова точно соответствует формату, требуемому внутренним методом.
catch me:
Знаю почти:Ли Цзяи