apply、call、bind 三者都是 Function 原型上的方法,也就是说,基本所有函数都可以通过 函数名.apply|call|bind
调用
apply、call、bind 三者用于函数调用,其与普通的函数调用区别在于参数的传递和this的指向,三者常用于绑定调用方法的主体,使得this 指向重新指向新的目标。
在使用方面,三者存在一些区别,下面依次介绍apply、call和bind
Function 实例的apply() 方法会以指定的this值和参数(数组形式)
调用该函数
apply(thisArg)
apply(thisArg, argsArray)
替换为全局对象
,原始值会被转换为对象。const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max);
// Expected output: 7
const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2
call() 方法会以给定的 this 值和逐个提供的参数调用该函数。
call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)
其中
使用 call() 调用函数并指定 this 值
function greet() {
console.log(this.animal, "的睡眠时间一般在", this.sleepDuration, "之间");
}
const obj = {
animal: "猫",
sleepDuration: "12 到 16 小时",
};
greet.call(obj); // 猫 的睡眠时间一般在 12 到 16 小时 之间
bind 和上面的apply 、call 有所区别,bind 方法将创建一个新函数
,当调用该新函数时,他会调用原始函数并将this关键字设置为指定的新的this对象,同时还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数前面
const module = {
x: 42,
getX: function () {
return this.x;
},
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42
bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)
bind() 函数可以进行多级绑定,如const boundFn = fn.bind(thisArg, arg1, arg2),
绑定函数可以通过调用 boundFn.bind(thisArg, /* more args */) 进一步进行绑定,从而创建另一个绑定函数 boundFn2,但需要注意的是,新绑定的 thisArg 值会被忽略,因为boundFn2目标是boundFn, boundFn的目标是fn。最终fn 接受的参数顺序是 boundFn 的绑定参数,boundFn2 绑定参数已经boundFn2 接受的参数
如下面的例子
function log(...args) {
console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6
boundLog.bind 会忽略 new this value ,从而形成上述的代码输出顺序,进而证明同时还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数前面
这句话
整理参数的顺序如下
apply和call 在效果上,基本是同等的,只是传入参数的方式不同,apply传入数组,call 可以连续传入单个参数
bind 和 call|apply 效果也是 同等的,你可以将 const boundFn = fn.bind(thisArg, arg1, arg2) 和 const boundFn = (…restArgs) => fn.call(thisArg, arg1, arg2, …restArgs) 构建的绑定函数的调用效果视为等效(但就构建 boundFn 的过程而言,不是二者等效的)
bind 在内部中,会返回一个新的函数,与apply 和call直接调用目标函数不同
bind 多级绑定,bind 的绑定参数会插入到调用新函数传入参数前面