We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
阅读lodash源码的时候, 发现了一个很奇怪的写法, 如下
function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); }
首先这是反柯里化的方法, 这不奇怪, 为了统一调用的代码组织方法. 但是里面的实现, 优先使用call来调用func,直到超过3个参数的时候, 才用apply, 而且使用的参数apply, 为什么不直接使用apply, 而在注释的那里找到了原因, call比 apply快.
call
func
apply
// A faster alternative to `Function#apply`, this function invokes `func` with the `this` binding of `thisArg` and the arguments of `args`.
这么一看, apply传的是数组, 而call, 的参数则是一个萝卜一个坑的, apply比call慢, 倒也正常. 毕竟需要检查和遍历赋值到调用函数接收的list.
list
测试一下
function callTest(){ console.time('call 9 prarameters'); var minInNumbers = Math.max.call(Math, 5, 4, 3, 333, -334.33, 323, 55555, -3405, 340359); console.timeEnd('call 9 prarameters'); } function applyTest(){ console.time('apply 9 prarameters'); Math.max.apply(Math, [5, 4, 3, 333, -334.33, 323, 55555, -3405, 340359]); console.timeEnd('apply 9 prarameters'); } var i = 0; while(i++<100){ callTest(); applyTest(); console.log(`------------${i}----------`) }
由上可知, 理论上call比apply快, 但是很难从程序的角度上去感知. 只能感性去理解了(反正我是测试不出来需要的效果了, 看到其他博主怎么辣么niuB?).
但是, 如果我们转化个角度, call因为在参数上调用, 天然吻合函数参数的list, 而apply函数, 因为参数需要转化, 赋值和类型检查, 耗损时间, 那么通过解构的运算...转化, 是不是就会好些?
...
const prarameterLength = 100000; let i = 0; while (++i < prarameterLength) { a.push(Math.random() * 10000); } function callTest1() { console.time(`call ${prarameterLength} prarameter`); var minInNumbers = Math.max.call(Math, ...a); console.timeEnd(`call ${prarameterLength} prarameter`); return minInNumbers; } function applyTest1() { console.time(`apply ${prarameterLength} prarameter`); var maxInNumbers = Math.max.apply(Math, a); console.timeEnd(`apply ${prarameterLength} prarameter`); return maxInNumbers; } let int = 0; while (++int < 100) { callTest1(); applyTest1(); console.log(`-------------${int}--------------`); }
如果参数的长度在100000那么大的差别下, call 的效率还是比较低的. 但是也可以方向证明, 也只有在巨大的参数数量下, 性能才体现出来. 在参数极少的情形下, 让call和apply之间的做性能对比也只是鸡蛋里面挑骨头, 因为差距几乎可以忽略不计.
看到ES6的标准内容. apply函数比call的函数多那么一个步骤, ECMA-6的call, ECMA-6的apply,
ES6
其中的createListFromArrayLike的方法细节繁多
createListFromArrayLike
总的来说有那么几条
对比call的方法调用, 没有那么多的类型检查, 这个也是大家觉得性能明细差别的原因.
https://ecma-international.org/ecma-262/6.0/#sec-createlistfromarraylike
https://ecma-international.org/ecma-262/6.0/#sec-function.prototype.call
call比apply 更快? 理论上是的, 但是实际也还看计算机的运行状态, 测试之中没有得到我想要的结果,因为参数方式不同, 运行时需要多个参数检查,但是这个影响太细微了,反而 计算机的运行状态对传参是否多几个判断的影响更大, 所以测试不出来
注: 本文的github地址为:lodash源码解读(8)-call真的比apply效率更快吗 如有版权问题,或其他问题, 请给作者留言,感谢!
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
阅读lodash源码的时候, 发现了一个很奇怪的写法, 如下
首先这是反柯里化的方法, 这不奇怪, 为了统一调用的代码组织方法.
但是里面的实现, 优先使用
call
来调用func
,直到超过3个参数的时候, 才用apply, 而且使用的参数apply, 为什么不直接使用apply
, 而在注释的那里找到了原因,call
比apply
快.这么一看,
apply
传的是数组, 而call
, 的参数则是一个萝卜一个坑的,apply
比call
慢, 倒也正常. 毕竟需要检查和遍历赋值到调用函数接收的list
.所以, call 比 apply 速度快多少?
测试一下
由上可知, 理论上
call
比apply
快, 但是很难从程序的角度上去感知. 只能感性去理解了(反正我是测试不出来需要的效果了, 看到其他博主怎么辣么niuB?).但是, 如果我们转化个角度,
call
因为在参数上调用, 天然吻合函数参数的list, 而apply函数, 因为参数需要转化, 赋值和类型检查, 耗损时间, 那么通过解构的运算...
转化, 是不是就会好些?解构的call 会比apply 快吗?
如果参数的长度在100000那么大的差别下, call 的效率还是比较低的. 但是也可以方向证明, 也只有在巨大的参数数量下, 性能才体现出来. 在参数极少的情形下, 让call和apply之间的做性能对比也只是鸡蛋里面挑骨头, 因为差距几乎可以忽略不计.
看到
ES6
的标准内容.apply
函数比call
的函数多那么一个步骤, ECMA-6的call, ECMA-6的apply,其中的
createListFromArrayLike
的方法细节繁多总的来说有那么几条
对比call的方法调用, 没有那么多的类型检查, 这个也是大家觉得性能明细差别的原因.
小结
call
比apply
更快? 理论上是的, 但是实际也还看计算机的运行状态, 测试之中没有得到我想要的结果,因为参数方式不同, 运行时需要多个参数检查,但是这个影响太细微了,反而 计算机的运行状态对传参是否多几个判断的影响更大, 所以测试不出来The text was updated successfully, but these errors were encountered: