在JavaScript中函数的调用除了可以直接调用,还可以为他绑定特定的this值,使用call、bind、apply 手写实现一个
call
首先看看系统的call
const obj = {name: "Allen"}
function sum(num1, num2) {
console.log("this", this)
return num1 + num2
}
sum.call(obj) // this { name: 'Allen' }
sum.call("abc") // this [String: 'abc']
接下来实现一下
要让所有的函数都拥有这个mycall方法,所以我们要在Function的原型链上添加
Function.prototype.mycall = function(){}
既然是添加到函数上的属性,到时候调用是通过对象的方法来调用的,例如sum.mycall()
作为对象的方法调用其 this 值会进行隐式绑定绑定到调用它的对象上,也就是调用它的函数,这样就可以获取到函数从而在mycall中对它进行调用
Function.prototype.mycall = function(thisArgs, ...rest) {
// 开始还需要判断传进来的是不是undefined和null,如果不是就进行Object处理
// 因为传进来的有可能是数字和字符串,而他们是不能添加属性的
thisArgs = thisArgs ? Object(thisArgs) : window
thisArgs.fn = this
const result = thisArgs.fn(...rest)
delete thisArgs.fn
return result
}
function sum(num1, num2) {
console.log("this", this)
return num1 + num2
}
const obj = {name: "Allen"}
const result1 = sum.mycall(obj, 1, 2)
const result2 = sum.mycall("abc", 1, 2)
结果如下:
实现成功
apply
apply和call是差不多的,就是传的参数第二个参数是要求为数组
Function.prototype.myapply = function(context, argArray) {
context = context ? Object(context) : window
context.fn = this
let result
if(argArray) {
result = context.fn(...argArray)
} else {
result = context.fn()
}
delete context.fn
return result
}
function sum(num1, num2) {
console.log("this", this)
return num1 + num2
}
const obj = {name: "Allen"}
const result = sum.myapply(obj, [20, 30])
console.log(result)
bind
bind和上面两个差别有些大,先看看系统的bind
function sum(num1, num2, num3, num4) {
console.log(num1, num2, num3, num4)
}
const obj = {name: "Allen"}
const newSum = sum.bind(obj, 10, 20)
newSum(30, 40) // 10 20 30 40
可以看到它这个传参数可以分开传,可以在bind的时候传一些,获取到新函数进行调用再传完剩余的参数
开始实现
Function.prototype.mybind = function(context, ...args) {
context = context ? Object(context) : window
context.fn = this
return function(...rest) {
const finalArgs = [...args, ...rest]
const result = context.fn(...finalArgs)
return result
}
}
function sum(num1, num2, num3, num4) {
console.log(this)
console.log(num1, num2, num3, num4)
return num1 + num2 + num3 + num4
}
const obj = {name: "Allen"}
const newSum = sum.mybind(obj, 10, 20)
newSum(30, 40)
注意bind这个函数最后不能把 context.fn 删除属性,否则得到的新函数只能调用一次