详解JS中call、apply、bind函数的实现原理

在JavaScript中,为我们提供了call、apply、bind三个方法,其作用都是用来手动绑定this指向,让我们一起来看看它们有什么共同点、区别,以及其实现上的不同:

共同点:

  1. 都是用来更改函数执行时this的指向
  2. 它们接受的第一个参数即为要绑定的this
  3. 都会接收剩余参数

区别:

  1. call、apply、bind传参上的不同,call、bind方法不限制参数个数,参数类型,而apply要求第二个参数必须是数组,且不再接收后续参数
  2. call、apply方法是立即调用,而bind方法只是绑定this,返回一个函数
  3. 由于bind方法返回函数,在函数再次调用时,可传入剩余参数

实现:

一、call的实现

var name = 'windows'

function foo(...args){
 console.log(this.name,args)   
}

const obj = {
    name: 'ttt'
}
// call实现
Function.prototype.myCall = function (thisArg,...agrs){
    // 获取调用方法
    const fn = this
    // 传入this是undefined或null时,默认指向window,否则转为对象,在浏览器下globalThis 则为window
    thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
    // 给对象添加属性
    thisArg.fn = fn
    // 调用更改this指向并传入剩余参数
    let res = thisArg.fn(...agrs)
    delete thisArg.fn
    return res
}

foo.myCall(obj,[1,2],33,44) 
// ttt [ 1, 2 ] 33 44

二、apply的实现

function foo(...args){
 console.log(this.name,...args)   
}

const obj = {
    name: 'ttt'
}

// apply实现
Function.prototype.myApply = function (thisArg,args){
    // args传入的参数需要是数组
    if(!Array.isArray(args)){
        throw new Error('CreateListFromArrayLike called on non-object')
    }
    // 获取调用方法
    const fn = this
    // 传入this是undefined或null时,默认指向window,否则转为对象
    thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
    // 给对象添加属性
    thisArg.fn = fn
    // 调用更改this指向并传入剩余参数
    let res = thisArg.fn(...args)
    delete thisArg.fn
    return res
}

foo.myApply(obj,[1,2]) // ttt 1 2

三、bind的实现

var name = 'windows'

function foo(...args){
 console.log(this.name,...args)   
}

const obj = {
    name: 'ttt'
}

// bind实现
Function.prototype.myBind = function (thisArg,...args){
    // 将传入的this转为对象
    thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
    // 给对象添加属性
    thisArg.fn = this
    // 返回function是因为bind方法返回一个函数
    return function (...residue){
        // 这里将参数合并在一起传入当前执行函数
        let res = thisArg.fn(...args.concat(residue))
        delete thisArg.fn
        return res
    }
}

foo.myBind(obj,1,2)(3,4) // ttt 1 2 3 4

有不懂的地方,欢迎留言交流~

今天的学习分享就到这里,下次让我们一起看看Promise的实现原理...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值