1. 原理
apply()
- 作用:apply 用于调用一个函数,并指定函数内部的 this 值以及传入的参数(参数必须是数组或者类数组对象)。
- 语法:func.apply(thisArg, [argsArray])
- thisArg:函数内的 this 指向的对象
- argsArray:一个数组或类数组对象,包含传递给函数的参数。
- 特点:apply 立即执行函数。参数传递的方式是数组或类数组。
call()
- 作用:call 和 apply 很相似,也用于改变函数内部的 this,但是参数传递的方式不同。call 接收的参数是逐个传递的,而不是数组。
- 语法:func.call(thisArg, arg1, arg2, ...)
- thisArg:函数内的 this 指向的对象。
- arg1, arg2, ...:逐个传递给函数的参数。
- 特点:call 立即执行函数。参数逐个传递,而不是作为数组传递。
bind()
- 作用:bind 创建一个新的函数,this 会绑定到指定的对象,并且可以选择性地传递参数。与 apply 和 call 不同,bind 不会立即执行函数,而是返回一个新的函数,可以在之后的某个时刻调用。
- 语法:const newFunc = func.bind(thisArg, arg1, arg2, ...)
- thisArg:新的 this 指向的对象。
- arg1, arg2, ...:预先传递给新函数的参数。
- 特点:bind 返回一个新的函数,并不会立即执行。可以预先传递一些参数,这些参数会被绑定在新函数中,后续调用时可以继续传入参数。
function showDetails(city, country) {
console.log(`${this.name} lives in ${city}, ${country}.`);
}
const person = { name: 'John' };
// 使用 call
showDetails.call(person, 'New York', 'USA');
// John lives in New York, USA.
// 使用 apply
showDetails.apply(person, ['New York', 'USA']);
// John lives in New York, USA.
// 使用 bind
const boundFunc = showDetails.bind(person, 'New York');
boundFunc('USA');
// John lives in New York, USA.
2. 手写实现
手写call()
Function.prototype.myCall = function (thisArg,...args){
// 如果 thisArg 为 null 或 undefined,则指向全局对象
thisArg = thisArg || globalThis;
// 创建一个唯一的属性来避免覆盖已有的属性
const uniqueKey = Symbol();
thisArg[uniqueKey] = this;
// 使用展开的 args 调用函数
const result = thisArg[uniqueKey](...args);
// 删除临时属性
delete thisArg[uniqueKey];
return result;
}
手写apply()
Function.prototype.myApply = function(thisArg, argsArray) {
// 如果 thisArg 为 null 或 undefined,则指向全局对象
thisArg = thisArg || globalThis;
// 创建一个唯一的属性来避免覆盖已有的属性
const uniqueKey = Symbol();
thisArg[uniqueKey] = this;
// 使用数组的方式执行函数
const result = thisArg[uniqueKey](...argsArray);
// 执行完毕后删除临时属性
delete thisArg[uniqueKey];
return result;
};
手写bind()
Function.prototype.myBind = function(thisArg, ...boundArgs) {
// 返回一个新的函数
const self = this;
// 返回的新函数,接受后续传入的参数
return function(...args) {
// 使用 apply 调用原始函数,绑定 this 并传递参数
return self.apply(thisArg, [...boundArgs, ...args]);
};
};