apply、call和bind都是系统提供给我们的内置方法,每个函数都可以使用这三种方法,是因为apply、call和bind都实现在了Function的原型上(Function.prototype),而他们的作用都是给我们函数调用时显式绑定上this。下面先介绍一下它们的基本用法:
call方法:使用一个指定的 this值和单独给出的一个或多个参数来调用一个函数。
function foo(x, y ,z) {
console.log(this, x, y, z)
}
const obj = { name: 'curry', age: 30 }
/**
* 1.将obj对象绑定给foo函数的this
* 2.call剩余参数中的a b c分别传递给foo函数对应的三个参数
*/
foo.call(obj, 'a', 'b', 'c')

apply方法:调用一个具有给定this值的函数,以及以一个**数组(或类数组对象)**的形式提供的参数。
function foo(x, y ,z) {
console.log(this, x, y, z)
}
const obj = { name: 'curry', age: 30 }
/**
* 1.将obj对象绑定给foo函数的this
* 2.数组中的1 2 3分别传递给foo函数对应的三个参数
*/
foo.apply(obj, [1, 2, 3])

bind方法:创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
function foo(...args) {
console.log(this, ...args)
}
const obj = { name: 'curry', age: 30 }
/**
* 1.将obj对象绑定给foo函数的this
* 2.bind剩余参数中的1 2 3分别传递给foo函数中参数
* 3.也可在newFoo调用时传入参数,这时bind传递的参数会与newFoo调用时传递的参数进行合并
*/
const newFoo = foo.bind(obj, 1, 2, 3)
newFoo()
newFoo('a', 'b', 'c')

function foo(...arg) {
console.log(this.name, ...arg);
}
function obj() {
this.name = 'obj'
}
Function.prototype.myCall = function(context, ...args) {
// 1. 检查上下文是否为 null 或 undefined,如果是则设置为全局对象(浏览器中为 window)
context = context || window;
// 2. 为上下文对象创建一个唯一属性来保存当前函数,
// 以便在调用完后删除这个属性,避免污染原始对象
const fnKey = Symbol();
context[fnKey] = this;
// 3. 通过上下文对象调用函数并传入参数
const result = context[fnKey](...args);
// 4. 删除添加的属性
delete context[fnKey];
// 返回函数调用结果
return result;
};
// 原始call方法
foo.call(obj, 1, 2, 3)
// 手写call方法
foo.myCall(obj, 1, 2, 3)
输出结果:

Function.prototype.myApply = function (context, args) {
// 1.检查上下文是否为 null 或 undefined,如果是则设置为全局对象(浏览器中为 window)
context = context || window;
// 2. 为上下文对象创建一个唯一属性来保存当前函数,
// 以便在调用完后删除这个属性,避免污染原始对象
const fnKey = Symbol();
context[fnKey] = this;
let result;
// 3. 检查是否传入了参数
if (args) {
// 使用扩展运算符展开参数数组,并通过上下文对象调用函数
result = context[fnKey](...args);
} else {
// 如果未传入参数则直接通过上下文对象调用函数
result = context[fnKey]();
}
// 4. 删除添加的属性
delete context[fnKey];
// 返回函数调用结果
return result;
};
foo.apply(obj, [1, 2, 3])
foo.myApply(obj, [1, 2, 3])
输出结果:

Function.prototype.myBind = function(context, ...args) {
const fn = this;
return function(...innerArgs) {
// 使用 apply 方法将传入的上下文和参数传递给函数,并返回调用结果
return fn.apply(context, [...args, ...innerArgs]);
};
};
let fn = foo.bind(obj,1,2,3)
let fn2 = foo.myBind(obj,1,2,3)
fn('a','b','c')
fn2('a','b','c')
输出结果:
