call、apply、bind 的区别
What are the differences between call, apply & bind
一句话:三个都是改this。call 和 apply立即执行,bind 返回一个新函数;call 参数一个个传,apply 传数组。
| 是否立即执行 | 参数形式 | |
|---|---|---|
fn.call(ctx, a, b) | 立即 | 逐个(Comma) |
fn.apply(ctx, [a, b]) | 立即 | 数组(Array) |
fn.bind(ctx, a) | 不执行,返回新函数 | 逐个,且可以只绑一部分 |
记法:Apply 收 Array,Call 用 Comma。
bind 的两个额外性质(追问点):
- 能预置参数—— 所以它就是偏函数 (见 #299)。
- 绑过一次就锁死了—— 再
bind或call都改不回来。但new能突破它, 因为new优先级最高。
还会追问:「apply 现在还有用吗?」—— 展开语法出来后大部分被fn(...args) 取代了。但转发不定参数时还常用:fn.apply(this, args)(防抖里就是这么写的,因为要同时转发this 和 args)。
In one line: all three change this. call and apply run the function right away, bind hands you back a new one; call takes its arguments one by one, apply takes an array.
| Runs immediately? | Argument form | |
|---|---|---|
fn.call(ctx, a, b) | Yes | One by one (Comma) |
fn.apply(ctx, [a, b]) | Yes | An array (Array) |
fn.bind(ctx, a) | No — you get a new function | One by one, and you may bind only some of them |
How to remember it: Apply takes an Array, Call takes Commas.
Two extra properties of bind they will probe:
- It can preset arguments — which makes it partial application (see #299).
- Bind once and it is locked — another
bindor acallcannot change it back. Butnewbreaks through, becausenewhas the highest priority.
Another follow-up: “Is apply still useful?” — spread syntax replaced most of it with fn(...args). It is still the normal way to forward an unknown argument list: fn.apply(this, args) — that is how debounce is written, because you have to forward this and args at the same time.