手写call
原理
将需要改变this指向的函数暂时性的设置为需要设置this指向的对象的函数。
代码
// 定义mycall方法,所有函数对象都是Function对象
Function.prototype.mycall = function (thisArg, ...args) {
// 设置this,此时this指向原函数,之后将指向thisArg
thisArg.f = this
// 接收剩余参数并得到结果
const res = thisArg.f(...args)
// 移除函数
delete thisArg.f
// 返回结果
return res
}
// 测试样例
const person = {
name: '南辞w'
}
function func(numA, numB) {
console.log(this)
console.log(numA, numB)
return numA + numB
}
const res = func.mycall(person, 2, 8)
console.log('返回值为', res)
调优
对象中可能会出现函数重名冲突,可以利用Symbol()进行处理
调优后代码
Function.prototype.mycall = function (thisArg, ...args) {
const key = Symbol('key')
thisArg[key] = this
const res = thisArg[key](...args)
delete thisArg[key]
return res
}
const person = {
name: '南辞w'
}
function func(numA, numB) {
console.log(this)
console.log(numA, numB)
return numA + numB
}
const res = func.mycall(person, 2, 8)
console.log('返回值为', res)
手写apply
原理
改变this的方法同上,但接收的参数为数组形式,可以之间用 '...' 来展开接收
代码
Function.prototype.myapply = function (thisArg, args) {
const key = Symbol('key')
thisArg[key] = this
const res = thisArg[key](...args)
delete thisArg[key]
return res
}
const person = {
name: '南辞w'
}
function func(numA, numB, numC) {
console.log(this)
console.log(numA, numB, numC)
return numA + numB + numC
}
const res = func.myapply(person, [2, 8, 10])
console.log('返回值为', res)
手写bind
原理
改变this指向同上,但是此函数返回的是新的函数,并且可以分批次传值,前后次序不要弄混了
代码
Function.prototype.mybind = function (thisArg, ...args) {
return (...reArgs) => {
return this.call(thisArg, ...args, ...reArgs)
}
}
const person = {
name: '南辞w'
}
function func(numA, numB, numC, numD) {
console.log(this)
console.log(numA, numB, numC, numD)
return numA + numB + numC + numD
}
const bindFunc = func.mybind(person, 1, 2)
const res = bindFunc(3, 4)
console.log('返回值为', res)