前几章有讲到this指向的问题,我们改变this指向有call,apply,bind三种方法,这三种方法都是挂载在原型链上的3个方法.今天这一章就来具体的学习一下.和Promise一样,我觉得手写是最能理解的方式之一.
call
有多个参数,第一个是函数的this,后面是你所需要传递的参数,会直接调用函数
// 挂载在函数的原型上
Function.prototype.MyCall = function (thisArg, ...args) {
//this指的是当前函数
let fn = this
// 判断传入的this是什么
thisArg = (thisArg === undefined || thisArg === null) ? window : Object(thisArg)
thisArg.fn = fn
//如果arg不存在,就将其设置为[],方便结构
args = args || []
let res = thisArg.fn(...args)
//执行完之后就删除该对象上的属性
delete thisArg.fn
return res
}
function fn () {
console.log(this);
}
fn.MyCall({a:1}) // {a:1}
apply
apply]2个参数,第一个是函数的this,第二个是参数的数组,会直接调用
Function.prototype.MyApply = function (obj, arg) {
let fn = this //this表示函数
// 如果要是obj为undefined或者null时,设置其为window,
// 如果是基本数据类型,则将其设置为对象类型
let thisArg = (obj === undefined || obj === null) ? window : Object(obj)
thisArg.fn = fn
arg = arg || [] //如果arg不存在,则直接赋值为[]
let res = thisArg.fn(...arg)
delete thisArg.fn
return res
}
bind
和call一样 但是不调用
Function.prototype.MyBind = function (obj, ...args1) {
let fn = this
let thisArg = (obj === undefined || obj === null) ? window : Object(obj)
return function (...args2) {
thisArg.fn = fn
let args = [...args1, ...args2]
let result = thisArg.fn(...args)
delete thisArg.fn
return result
}
}