这是一个非常有意思的问题。

在看源码的过程中,总会遇到这样的写法:

 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 )

作者会在参数为3个(包含3)以内时,优先使用 call 方法进行事件的处理。而当参数过多(多余3个)时,才考虑使用 apply 方法。
这个的原因就是 call 比 apply 快。 
 
网上有很多例子全方位的证明了 call 比 apply 快。大家可以看看 call和apply的性能对比 这篇文章中的例子,很全面。或者你也可以自己写几个简单的,测试一下。这里要推荐一个神奇网站 jsperf ,用于测试 js 性能。
 
几个简单的例子:

 
 
为什么call 比apply 快?
这里就要提到他们被调用之后发生了什么。 
 

Function.prototype.apply (thisArg, argArray)

1、如果IsCallable(Function)为false,即Function不可以被调用,则抛出一个TypeError异常。
2、如果argArray为null或未定义,则返回调用function的[[Call]]内部方法的结果,提供thisArg和一个空数组作为参数。
3、如果 Type(argArray)不是Object,则抛出TypeError异常。
4、获取argArray的长度。调用argArray的[[Get]]内部方法,找到属性length。 赋值给len。
5、定义 n 为ToUint32(len)。ToUint32(len)方法:将其参数len转换为范围为0到2^32-1的2^32个整数值中的一个。
6、初始化 argList 为一个空列表。
7、初始化 index 为 0。
8、循环迭代取出argArray。重复循环 while(index < n)
            a、将下标转换成String类型。初始化 indexName 为 ToString(index).
            b、定义 nextArg 为 使用 indexName 作为参数调用argArray的[[Get]]内部方法的结果。
            c、将 nextArg 添加到 argList 中,作为最后一个元素。
            d、设置 index = index+1
9、返回调用func的[[Call]]内部方法的结果,提供thisArg作为该值,argList作为参数列表。

Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )

1、如果 IsCallable(Function)为false,即Function不可以被调用,则抛出一个TypeError异常。
2、定义argList 为一个空列表。
3、如果使用超过一个参数调用此方法,则以从arg1开始的从左到右的顺序将每个参数附加为argList的最后一个元素
4、返回调用func的[[Call]]内部方法的结果,提供thisArg作为该值,argList作为参数列表。

我们可以看到,明显apply比call的步骤多很多。
由于apply中定义的参数格式(数组),使得被调用之后需要做更多的事,需要将给定的参数格式改变(步骤8)。 同时也有一些对参数的检查(步骤2),在call中却是不必要的。
另外一个很重要的点:在apply中不管有多少个参数,都会执行循环,也就是步骤6-8,在call中也就是对应步骤3 ,是有需要才会被执行。

综上,call 方法比 apply 快的原因是 call 方法的参数格式正是内部方法所需要的格式。

 

 
 
 
 

【 js 基础 】为什么 call 比 apply 快?的更多相关文章

  1. js基础篇——call/apply、arguments、undefined/null

    a.call和apply方法详解 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象 ...

  2. 前端工程师面试问题归纳(一、问答类html/css/js基础)

    一.参考资源 1.前端面试题及答案整理(一) 2.2017年前端面试题整理汇总100题 3.2018最新Web前端经典面试试题及答案 4.[javascript常见面试题]常见前端面试题及答案 5.W ...

  3. JS中的call、apply、bind方法

    JS中的call.apply.bind方法 一.call()和apply()方法 1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]] ...

  4. js基础查漏补缺(更新)

    js基础查漏补缺: 1. NaN != NaN: 复制数组可以用slice: 数组的sort.reverse等方法都会改变自身: Map是一组键值对的结构,Set是key的集合: Array.Map. ...

  5. js基础进阶--关于Array.prototype.slice.call(arguments) 的思考

    欢迎访问我的个人博客:http://www.xiaolongwu.cn Array.prototype.slice.call(arguments)的作用为:强制转化arguments为数组格式,一般出 ...

  6. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  7. js基础面试篇

    1,js中的new做了什么? function Person () { this.name = name; this.age = age; this.sex = sex this.sayName = ...

  8. js基础梳理-关于this常见指向问题的分析

    首先,依然回顾<js基础梳理-究竟什么是执行上下文栈(执行栈),执行上下文(可执行代码)?>中的 3.执行上下文的生命周期 3.1 创建阶段 生成变量对象(Variable object, ...

  9. 为什么call比apply快

    这是一个非常有意思的问题. 在看源码的过程中,总会遇到这样的写法: var triggerEvents = function(events, args) { var ev, i = -1, l = e ...

随机推荐

  1. TmsHttpClientUtil

    package com.sprucetec.tms.utils; import java.io.IOException;import java.security.GeneralSecurityExce ...

  2. java项目配置域名(tomcat直接配置 or 使用nginx反向代理)

    一:  tomcat直接配置域名:https://blog.csdn.net/qq_36330228/article/details/78516160 二: 使用nginx进行反向代理 tomcat服 ...

  3. 【5】JMicro微服务-熔断降级

    如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl   1. 使用服务熔断降级特性,必须先启动Pubsub服务,服务监听服务,熔断器服务3个服务 先启动Pubsub及服务监听两 ...

  4. IIS 301重定向 报错 地址后面有eurl.axd

    错误发生的原因是当ASP.NET检测到Web站点配置为使用ASP.NET 4.0,本地ASP.NET 4.0 的组件会传递一个不能扩展的 URL到ASP.NET的管理程序作进一步处理.但是,如果一个低 ...

  5. 01-01java概述 doc命令、jdk\jre下载安装、path、classpath配置、开发中常见小问题

    1:计算机概述(了解) (1)计算机 (2)计算机硬件 (3)计算机软件 系统软件:window,linux,mac 应用软件:qq,yy,飞秋 (4)软件开发(理解) 软件:是由数据和指令组成的.( ...

  6. numpy中int类型与python中的int

    [code] import numpy as np nparr = np.array([[1 ,2, 3, 4]]) np_int32 = nparr[0][0] # np_int=1 py_int ...

  7. 整理几个 RPC 框架

    gRPChttp://www.grpc.io/https://github.com/grpcMotan支撑微博千亿调用的轻量级RPC框架:Motanhttp://h2ex.com/820WangleW ...

  8. ASP.NET Core 1.0 中 EntityFramework 与 PostgreSQL 的使用

    https://docs.efproject.net/en/latest/providers/npgsql/index.html 前面在CentOS6.7环境下配置好了PostgreSQL, 就顺便试 ...

  9. [java工具类01]__构建格式化输出日期和时间的工具类

    在之前的学习中,我写过一篇关于字符串格式化的,就主要设计到了时间以及日期的各种格式化显示的设置,其主要时通过String类的fomat()方法实现的. 我们可以通过使用不同的转换符来实现格式化显示不同 ...

  10. Python学习--11 面向对象高级编程

    多重继承 Python里允许多重继承,即一个类可以同时继承多个类: class Mammal(Animal): pass class Runnable(object): def run(self): ...