上一节,我们知道了解了call、apply和bind之间的区别和用法,本节咱们手写实现这三个方法。
首先我们知道 这三个方法目的都是为了改变this指向
,三个函数的用法基本相似:fn(target, arguments)
,只有bind不同,它需要手动执行 fn(target, arguments)()
,都是一个目标对象 target
,和参数 arguments
call, apply, bind 其实挂载在 Function
的 原型链prototype
上,都是在特定的作用域中调用函数,所以我们手写该方法也是在原型上
扩展。
手写call
let obj = { name: '小红' } let callFn = function (name) { console.log('我的名字', name) } callFn.call(obj, '小明') // 手写 Function.prototype._call = function (target, arguments) { // 在Function对象原型上进行扩展 target = target || window // 如果target 找不到则此时指向为window对象 target.fn = this // 将函数的this对象,赋值给目标对象的fn函数 let res = target.fn(...arguments) // 调用target.fn, 此时的this指向为目标对象 delete target.fn // 删除target的fn属性 return res // 返回结果 } callFn._call(obj, '小明') // 我的名字 小明
手写apply
let obj = { name: '小红' } let applyFn = function (name) { console.log('我的名字', name) } applyFn.apply(obj, ['小明']) // 手写 Function.prototype._apply = function (target, arguments) { // 在Function对象原型上进行扩展gy target = target || window // 如果target 找不到则此时指向为window对象 target.fn = this // 将函数的this对象,赋值给目标对象的fn函数 let res = target.fn(...arguments) // 调用target.fn, 此时的this指向为目标对象 delete target.fn // 删除target的fn属性 return res // 返回结果 } applyFn._apply(obj, ['小明'])() // 我的名字 小明
手写bind
let obj = { name: '小红' } let bindFn = function (name) { console.log('我的名字', name) } bindFn.bind(obj, '小明') // 手写 Function.prototype._bind = function (target, arguments) { // 在Function对象原型上进行扩展 // 因为bind不是立即执行,所以要返回一个函数,将结果返回出去 return function (...arguments) { target = target || window // 如果target 找不到则此时指向为window对象 target.fn = this // 将函数的this对象,赋值给目标对象的fn函数 let res = target.fn(...arguments) // 调用target.fn, 此时的this指向为目标对象 delete target.fn // 删除target的fn属性 return res // 返回结果 } } bindFn._bind(obj, '小明')() // 我的名字 小明
其实总体而言,也没有想象中那么难,只要了解其作用和原理,就可以写出来。如有不明白的或者写的有问题的话,请留言指正~,谢谢!