相同点
都可以改变函数内部的this指向
接收的第一个参数都是this要指向的对象
都可以利用后续参数传参
不同点
call和bind传参相同,多个参数依次传入的
apply只有两个参数,第二个参数为数组
call和apply都是对函数进行直接调用,而bind方法不会立即调用函数,而是返回一个修改this后的函数
call的用法
fn.call(thisArg, arg1, arg2, arg3, ...)
调用fn.call时会将fn中的this指向修改为传入的第一个参数thisArg;将后面的参数传入给fn,并立即执行函数fn。
let obj = {
name : '张三',
age : 25,
sayHello : function (hobby, address) {
console.log(`我是${this.name},今年${this.age}岁,我的爱好是${hobby},我的家乡是${address}`)
}
}
obj.sayHello('打篮球','杭州') //我是张三,今年25岁,我的爱好是打篮球,我的家乡是杭州
let obj1 = {
name : '李四',
age : 20,
}
obj.sayHello.call(obj1,'画画','合肥') //我是李四,今年20岁,我的爱好是画画,我的家乡是合肥
apply的用法
apply(thisArg, [argsArr])
fn.apply的作用和call相同:修改this指向,并立即执行fn。区别在于传参形式不同,apply接受两个参数,第一个参数是要指向的this对象,第二个参数是一个数组,数组里面的元素会被展开传入fn,作为fn的参数。
let obj = {
name : '张三',
age : 25,
sayHello : function (hobby, address) {
console.log(`我是${this.name},今年${this.age}岁,我的爱好是${hobby},我的家乡是${address}`)
}
}
obj.sayHello('打篮球','杭州') //我是张三,今年25岁,我的爱好是打篮球,我的家乡是杭州
let obj2 = {
name : '王五',
age : 10,
}
obj.sayHello.apply(obj2,['跳舞','合肥']) //我是王五,今年10岁,我的爱好是跳舞,我的家乡是合肥
bind的用法
bind(thisArg, arg1, arg2, arg3, ...)
fn.bind的作用是只修改this指向,但不会立即执行fn;会返回一个修改了this指向后的fn。需要调用才会执行:bind(thisArg, arg1, arg2, arg3, ...)()
。bind的传参和call相同。
let obj = {
name : '张三',
age : 25,
sayHello : function (hobby, address) {
console.log(`我是${this.name},今年${this.age}岁,我的爱好是${hobby},我的家乡是${address}`)
}
}
obj.sayHello('打篮球','杭州') //我是张三,今年25岁,我的爱好是打篮球,我的家乡是杭州
let obj3 = {
name : '陈六',
age : 60,
}
// obj.sayHello.bind(obj3,'唱歌','合肥') //无输出
obj.sayHello.bind(obj3,'唱歌','合肥')() //我是王五,今年10岁,我的爱好是唱歌,我的家乡是合肥
手写call
Function.prototype.myCall = function (obj) {
obj = obj || window; //当传入的参数为 null/undefined 时指向window
obj.fn = this; //相当于在obj对象添加fn方法 // this是指调用myCall的函数
let args = [...arguments].slice(1)
let result = obj.fn(...args);
delete obj.fn //原来的obj中没有fn方法 所以要删除
return result
}
//测试
function Fn(a,b,c,d) {
console.log(this.name,a,b,c,d)
}
const o = {
name : '张三',
}
Fn.myCall(o,1,2,3,4,5) //张三 1 2 3 4
手写apply
Function.prototype.myApply = function (obj) {
obj = obj || window
obj.fn = this;
let result;
if (arguments[1]){
result = obj.fn(...arguments[1])
}else{
result = obj.fn()
}
delete obj.fn;
return result;
}
//测试
function Fn(a,b,c,d) {
console.log(this.name,a,b,c,d)
}
const o = {
name : '张三',
}
Fn.myApply(o,[1,2,3,4]) //张三 1 2 3 4
手写bind
Function.prototype.myBind = function (obj) {
let that = this; //this指向调用myBind的函数
let args = [...arguments].slice(1)
return function () { //bind返回的是函数
//这里面的this指向window
let arg = [...args, ...arguments] //这里面的arguments为里面函数的arguments
return that.apply(obj,arg)
}
}
function Fn(a,b,c,d) {
console.log(this.name,a,b,c,d)
}
const o = {
name : '张三',
}
Fn.myBind(o,1,2,)(3,4) //张三 1 2 3 4