它们的作用都是改变 this 指向
call:fn.call(obj, args1, args2, args3...)
Function.prototype.newCall = function(context, ...args) {
// 处理参数:this 指向的新对象,兜底为 window
context = context || window
// 当前 this 指向调用该方法的函数,即函数本身
const fn = this
// 声明唯一值,作为 新对象 的 key
const key = Symbol('context-key')
// 将函数本身赋值到新对象上
context[key] = fn
// 在新对象上调用函数,传入后续的参数,则实现了 this 指向的改变
// 因为函数是在对象上调用的,所以函数内的 this 将指向该对象
const result = context[key](...args)
// 删除刚刚赋值的 key,解绑
delete context[key]
// 返回函数执行的结果
return result
}
// 示例函数:
function fn(callName, callFnName) {
console.log(callName)
console.log(callFnName)
console.log(this.name)
}
// 示例调用:
fn.newCall({ name: '张三' }, '张三 call 的', 'newCall')
// 打印结果:
// '张三 call 的'
// 'newCall'
// '张三'
那对应的 apply,只需要更改下函数定义参数的写法
fn.apply(obj, [args1, args2, args3...])
Function.prototype.newApply = function(context, args) {
// 里面的内容完全不变
}
// 示例调用:第二个参数改为数组
fn.newApply({ name: '张三' }, ['张三 apply 的', 'newApply'])
// 打印结果:
// '张三 apply 的'
// 'newApply'
// '张三'
那对应的 bind 本质可以借助上面的call/apply实现
fn.bind(obj, args1, args2, args3...)()
Function.prototype.newBind = function(context, ...args) {
// 处理参数:this 指向的新对象,兜底为 window
context = context || window
// 当前 this 指向调用该方法的函数,即函数本身
const fn = this
return function(..._args) {
return fn.newApply(context, args.concat(_args))
}
}
// 示例函数:
function fn(callName, callFnName) {
console.log(callName)
console.log(callFnName)
console.log(this.name)
}
// 示例调用:
const bindFn = fn.newBind({ name: '张三' }, '张三 bind 的', 'newBind')
bindFn()
// 打印结果:
// '张三 bind 的'
// 'newBind'
// '张三'