从原生的角度理解call、apply、bind的实现
call
方法的实现
function myFunction() {
console.log(this.name);
}
let myObj = { name: "剑魂" };
Function.prototype.myCall = function (obj) {
console.log(this); //这里的this指向的是谁?
};
myFunction.myCall(myObj);
复制代码
首先我们需要明白,在上边的代码中我们的
this
指向的是谁?不明白的可以点击这里关于this的指向问题。我们可以知道此时当myFunction函数调用myCall的时候this指向myFunction
函数。由此我们可以推断出以下写法:
function myFunction() {
console.log(this.name);
}
function sum( job1, job2) {
console.log("sum函数被执行", this, job1, job2);
return job1 + '和' + job2 + this.name
}
let myObj = { name: "剑魂" };
Function.prototype.myCall = function (obj, ...newArr) {
console.log(this); // 1.这里的this指向的是函数myFunction
// 2.对obj转成对象类型(防止它传入得是非对象类型) 不然会报错
obj = (obj !== null && obj !== undefined) ? Object(obj) : window
obj.fn = this; // 3.给obj对象添加一个key为fn的方法,把函数myFunction赋值给fn次方法
let result = obj.fn(...newArr); // 4.这里可以调用函数myFunction,得到函数内部打印为 “剑魂”
delete obj.fn // 5.删除对象obj中的fn,不让对象中多出新方法
return result // 6.将有返回值的函数返回值返回
};
myFunction.myCall(myObj);
let result = sum.myCall(myObj, "肥鯮", "井盖", "不锈钢换盆")
console.log(result); // 肥鯮和井盖剑魂
复制代码
到这里我们的call方法就完成了,是不是更加清楚了。从这里我们可以知道`call`的特点:
复制代码
call
的参数是一共有2个,第一个为绑定this的是谁,第二个是一个参数列表。call
方法调用完是立即执行,并且存在返回值。
apply
方法的实现
`apply`方法的实现其实和call很相似,不同点就是参数处理方面不同,来往下看看吧:
复制代码
// 实现自己的apply
Function.prototype.myapply = function (obj, newArray = []) {
console.log(this); // 1.这里的this指向的是函数myFunction
// 2.处理绑定的obj,防止传入不是一个对象报错
obj = (obj !== null && obj !== undefined) ? Object(obj) : window
// 3.把函数绑定到对象上
obj.fn = this
// 4.执行函数并得到函数的返回值
let result = obj.fn(...newArray)
delete obj.fn
// 5.返回结果
return result
}
function myFunction(name) {
console.log(name);
}
function sum(job1, job2) {
console.log("sum函数被执行", this, job1, job2);
return job1 + '和' + job2 + this.name
}
let myObj = { name: "剑魂" };
// 自己实现调用
var result = sum.myapply('abc', ['肥鯮', '不锈钢换盆'])
console.log(result);
var result2 = myFunction.myapply("abc", ['剑魂'])
console.log(result2)
复制代码
从这里我们可以知道`apply`的特点:
复制代码
apply
的参数是一共有2个,第一个为绑定this的是谁,第二个是数组形式的对象参数。apply
方法调用完是立即执行,并且存在返回值。
bind
方法的实现
// 实现自己的apply
Function.prototype.mybind = function (obj, ...newArray) {
console.log(this); // 1.这里的this指向的是函数myFunction
let that = this
// 2.处理绑定的obj,防止传入不是一个对象报错
obj = (obj !== null && obj !== undefined) ? Object(obj) : window
// 定义一个新的bind执行函数返回
function proxyFn(...args) {
obj.fn = that
// 特殊:对两个传入的参数进行合并
var arrList = [...newArray, ...args]
// 执行函数得到返回值
var result = obj.fn(...arrList)
// 删除新增的函数
delete obj.fn
// 4.返回结果
return result
}
// 5.返回结果
return proxyFn
}
function myFunction(name) {
console.log(name);
}
function sum(job1, job2) {
return job1 + '和' + job2
}
// 自己实现调用
var result = sum.mybind('abc', '肥鯮', '不锈钢换盆')
console.log(result());
var result2 = myFunction.mybind("abc", '剑魂')
console.log(result2())
复制代码
从这里我们可以知道 bind 的特点:
复制代码
bind
的参数是一共有2个,第一个为绑定this的是谁,且只能改变一次函数的this指向,后续再用bind更改无效;第二个是参数形式的参数。bind
方法调用成返回一个函数,需要再次调用此函数得到结果。