【JavaScript】手写call、apply、bind函数,理清楚思路其实不难。

一、call、apply、bind的作用和区别

JavaScript中call、apply、bind函数的作用都一样,都是改变函数中的this指向。它们之间只有一些细小的差别:

  • call,第一个参数为执行上下文,参数通过后续参数传递,会自动调用函数
  • apply,第一个参数为执行上下文,参数需要写成一个数组,然后通过第二个参数传递,会自动调用函数
  • bind,与call几乎一模一样,只是不会自动调用函数,需要手动调用。

二、实现思路

两个函数A、B。当A调用call、apply、bind函数时需要传入函数B的执行上下文B和参数。

想要将B的this指向A只需要

  • 在B的执行上下文this中创建一个函数,函数保存着A中的执行上下文this。
  • 这样只要通过B的执行上下文调用这个函数,就达到了改变this的效果,B可以读取A中的变量
  • 最后再删除这个函数

三、代码实现

上面看不懂没关系,直接上代码 + 注释

手写call

Function.prototype.myCall = function(context,...args){
    // 如果调用者不是函数,直接返回
    if(typeof this !== "function"){
        return "Type Error"
    }

    // context为传入的执行上下文
    // 判断是否有传入context上下文,如果有就取传入的上下文,否则就指向window

    //例如:A.myCall(this),这里this为B函数的this。
    //此时context就是B的this
    context = context || window;


    // 在传入的执行上下文内创建调用call的函数,这样就改变了this指向
    //此时context是B的this,this是A的this。在B的执行上下文中创建了一个函数fn,保存A的this
    context.fn = this


    // 判断是否有传入参数,如果有参数,就放入函数执行一遍,否则就直接执行一次

    //此时通过B的this调用这个函数,由于this会指向调用者,fn的this就会指向B
    //由于fn中的内容和A中的内容是一样的,相当于B的this指向了A
    context.fn(...args)


    // 执行完后,将创建的函数删除
    delete context.fn;
}

手写apply

Function.prototype.myApply = function(context,arr = []){
    // 如果调用者不是函数,直接返回
    if(typeof this !== "function"){
        return "Type Error"
    }
    context = context || window;

    context.fn = this;

    context.fn(...arr)

    delete context.fn
}

手写bind


Function.prototype.myBind = function(context,...args){
    // 如果调用者不是函数,直接返回
    if(typeof this !== "function"){
        return "Type Error"
    }
    // context为传入的执行上下文

    // 判断是否有传入context上下文,如果有就取传入的上下文,否则保持当前上下文
    context = context || window;

    // 由于bind函数不会立即调用函数,所以直接返回一个回调函数,当调用的时候才改变this指向
    return(args)=>{this.call(context,...args)}

}

四、测试

    function A(age, like) {
      this.name = "喵喵";
      this.age = age;
      this.like = like;
    }

    function B() {
      A.call(this, 5, "鱼");
      A.myCall(this, 5, "鱼");
      console.log("call", this.name, this.age, this.like);
      console.log("myCall", this.name, this.age, this.like);

      A.apply(this, [5, "鱼"]);
      A.myApply(this, [5, "鱼"]);
      console.log("apply", this.name, this.age, this.like);
      console.log("myApply", this.name, this.age, this.like);

      A.bind(this, 5, "鱼")();
      A.myBind(this, 5, "鱼")();
      console.log("bind", this.name, this.age, this.like);
      console.log("myBind", this.name, this.age, this.like);
    }

    B();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值