他们都是JS中改变this指向的方法,区别在于:
call和apply都是立即执行函数,他们的第一个参数都是函数调用时this的值,但是call的剩余参数为多个,依次传入,apply的剩余参数为一个数组;
bind和call的用法基本一样,但是bind会返回一个新的函数,所以bind不是立即执行函数,它的作用是延迟调用,可以用一个方法x来接受函数调用的bind函数,而且这个x方法也可以传入参数。
1.实现一个call函数:
function person() {
console.log(this.name);
}
let egg = {
name: 'hhh',
}
Function.prototype.newCall = function(obj) {
obj.p = this; // 将调用 newCall 的函数(即 person 函数)赋值给 obj 的 p 属性,
//此时p属性就相当于person函数了。
obj.p(); // 调用 obj 的 p 方法(即 person 函数),此时 this 指向 obj。
//这时立即执行了obj.p(),也就是egg.p(),也就是egg.person()。
//此时相当于person 函数被egg对象调用,所以其中的 this 指向是 egg 对象
delete obj.p; // 删除 obj 上的 p 属性,清理环境
};
person.newCall(egg);//输出hhh
但是真正的call函数是可以传入多个参数的,再加以修改:
function person() {
console.log(this.name);
}
let egg = {
name: 'hhh',
};
Function.prototype.newCall = function(obj, ...args) {
obj.p = this;
obj.p(...args);
delete obj.p;
};
// 测试示例
person.newCall(egg); // 输出:hhh
// 传递多个参数的示例
//call函数传入多个参数,本质上是调用call函数的那个函数需要接受多个参数
function greet(a, b) {
console.log(`${a}, ${this.name}${b}`);
}
greet.newCall(egg, 'Hello', '!'); // 输出:Hello, hhh!
2.实现一个apply函数:
//apply和call函数只是传参有所区别,所以只改传参的方式即可
//call第二个参数为多个,apply第二个参数为一个数组
function person() {
console.log(this.name);
}
let egg = {
name: 'hhh',
};
Function.prototype.newApply = function(obj, argsArray) {
obj.p = this;
obj.p(...argsArray);
delete obj.p;
};
// 测试示例
person.newApply(egg, []); // 输出:hhh
// 传递多个参数的示例
function greet(a, b) {
console.log(`${a}, ${this.name}${b}`);
}
greet.newApply(egg, ['Hello', '!']); // 输出:Hello, hhh!
3.实现一个bind函数:
Function.prototype.newBind = function(obj, ...args) {
// 保存当前函数的引用
// 此时fn就是sayHello函数
let fn = this;
// 返回一个新的函数
// innerArgs 是指绑定后返回的新函数(即闭包)的参数列表
//这里也就是sayHello的参数列表
return function(...innerArgs) {
// 在新函数中调用原函数,并指定 this 和参数
// this指向为第一个参数
// 这时候相当于返回的是person调用的sayHello函数的apply执行
return fn.apply(obj, [...args, ...innerArgs]);
};
};
let person = {
name: 'hhh'
};
function sayHello(a,b) {
//this指向此时为person
console.log(`${a}, ${this.name}!,${b}`);
}
// 使用 bind 方法将 sayHello 函数绑定到 person 对象上
// args参数此时是'Hi'
let boundFunction = sayHello.newBind(person, 'Hi');
// 调用绑定后的函数
// 'kkkkk'就是innerArgs参数
boundFunction('kkkkk'); // 输出: Hi, hhh!