首先,call、apply、bind三者的作用均是改变函数中 this 的指向,如:
var c = 'window--c';
var obj = {
c: 'obj-c'
};
function fn(a, b) {
console.log(a, b, this.c);
}
// console.log -> "a", "b", "window-c"
fn('a', 'b');
// console.log -> "call-a", "call-b", "obj-c"
fn.call(obj, 'call-a', 'call-b');
// console.log -> "apply-a", "apply-b", "obj-c"
fn.apply(obj, ['apply-a', 'apply-b']);
// console.log -> "bind-a", "bind-b", "obj-c"
fn.bind(obj)('bind-a', 'bind-b');
从代码中,也可看出:
- call和apply是直接执行函数,同时改变 this 指向,只是参数形式不一样。
- bind 是返回一个新的改变了 this 指向的函数。
很多人可能会好奇,仅仅为了改变 this 的指向,为什么要有这么多方法。
其实,这三个方法使用上各有差别,若能熟练使用,会让代码写的更加精巧。
下面,这三种方法,各举一例:
借用其他类型变量的原生方法:
// 以数组的 join 方法为字符串加分隔符:
Array.prototype.join.call('abced', '-'); // "a-b-c-e-d"
让不识别数组的原生方法,识别数组
// 求数组中的最大值:
Math.max.apply(null, [9, 32, 1, 87, 4]); // 87
函数的柯里化(偏函数)
对函数式编程不熟悉的同学,可参考这篇《javascript中的函数式编程》
const pow2 = Math.pow.bind(null, 2);
pow2(4); // 16
pow2(5); // 32
诸如此类的“奇技淫巧”还有很多,只要应用得当,定能事半功倍。