call、apply和bind方法的使用
call
function setName(name,age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18
};
setName.call(person, "李四", 20);
console.log(person.name);
console.log(person.age);
apply
function setName(name, age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18
};
setName.apply(person, ["李四", 20]);
console.log(person.name);
console.log(person.age);
bind
function setName(name, age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18
};
const result = setName.bind(person, "李四", 20);
console.log(person.name);
console.log(person.age);
result();
console.log(person.name);
console.log(person.age);
它们的区别
| 参数 | 执行时机 |
---|
call | call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表,当第一个参数为null、undefined的时候,默认指向window。 | 调用的时候,会立即执行 |
apply | apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window | 同call |
bind | 同call | bind会返回一个值,值为一个函数,this指向传入的第一个参数对象,后续的参数列表会传递给这个返回值函数 |
对它们进行分析
为什么我们定义的setName,可以直接调用call、apply、bind方法
试着console.log(setName.__proto__.call);你会发现在原型
上有call方法,同理也有apply和bind方法。这是因为js在
Function构造函数的prototype上添加了call,bind,apply
方法。当我们声明一个函数时,实际上就是执行了new Function(),
因此我们定义的函数实例身上也有对应的方法。
为什么setName中的this.name的this指向person
从这点可知,call方法肯定帮我们做了处理。在call方法中的this
指向调用者,call在内部将this指向的实例的this指向了传入的
第一个参数。可能有点绕,从后面代码中分析可能会比较好理解。
apply,bind同理。
为什么传递给它们的参数都可以作为参数传递给我们定义的setName函数
call方法可以接收到所有的参数,然后call方法中的this指向了
调用者,call方法在内部将参数传递给了this指向的调用者。
apply,bind同理。
手写实现
call
function setName(name, age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18,
};
Function.prototype.newCall = newCall;
function newCall(obj, ...args) {
if (obj === null || obj == undefined) {
obj = global;
}
Object.prototype._fn = this;
obj._fn(...args);
delete Object.prototype._fn;
}
setName.newCall(person, "李四", 20);
console.log(person.name);
console.log(person);
setName.newCall(null, "李四", 20);
console.log(global.name);
console.log(global.age);
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/016d65742e1f3c338db96dfa9337f66b.png)
apply
function setName(name, age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18,
};
Function.prototype.newApply = newApply;
function newApply(obj, arr) {
if (obj === null || obj == undefined) {
obj = global;
}
Object.prototype._fn = this;
obj._fn(...arr);
delete Object.prototype._fn;
}
setName.newApply(person, ["李四", 20]);
console.log(person.name);
console.log(person);
setName.newApply(null, ["李四", 20]);
console.log(global.name);
console.log(global.age);
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8c9cd0efd573c48369abb428618cf653.png)
bind
function setName(name, age) {
this.name = name;
this.age = age;
}
const person = {
name: "张三",
age: 18,
};
Function.prototype.newBind = newBind;
function newBind(obj, ...args) {
if (obj === null || obj == undefined) {
obj = global;
}
return () => {
Object.prototype._fn = this;
obj._fn(...args);
delete Object.prototype._fn;
};
}
const result1 = setName.newBind(person, "李四", 20);
console.log(person.name);
console.log(person);
console.log("-------------------");
result1();
console.log(person.name);
console.log(person);
const result2 = setName.newBind(null, "李四", 20);
console.log("-------------------");
console.log(global.name);
console.log(global.age);
result2();
console.log("-------------------");
console.log(global.name);
console.log(global.age);
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6a97de4228b76e39c6f223db8f37538a.png)