一文读懂call、apply、bind的区别

55 篇文章 4 订阅
35 篇文章 1 订阅

1 简介

call、capply、bind他们三个是函数的方法;

使用场景:如果一个对象想借用别的对象的某个方法,可以使用这三个方法。即如果自己没有方法,但别人有我们就可以去借用,不用自己实现了;

区别:

(1) 功能

call和apply效果一样,使用该方法的时候,会立刻执行借用的函数;

bind先获取到该借用的方法,暂不执行;

(2) 用法

call和bind一样,第一个参数是替换内部this的对象,后面是要调用函数的参数;

apply第一个参数是替换内部this的对象,后面是一个参数数组;

2 基础用法-如何调用

首先我们定义两个对象,一个小白,一个小杨

// 小白对象
let xiaobai={
    name:"小白",
    pet:"splider"
} 


// 小杨对象
let xiaoyang={
    name:'小杨',
    pet:'pig',
    say:function(){
        console.log(`${this.name}有一只${this.pet}宠物`)
    }
}

如果想输出一个结果:小白有一只宠物蜘蛛

恰好咱了解到小杨对象有一个方法可以输出这句话;所以小白对象就想能不能借用他这个方法,答案是肯定可以啊,用call、apply、bind都可以

 (1)用call借用:

// 这是小杨自己的方法
xiaoyang.say();       // 小杨有一只pig宠物
// 小白借用了小杨的say函数,输出自己想要的结果     
xiaoyang.say.call(xiaobai)  // 小白有一只splider宠物

 所以小白借用小杨的say函数实现了自己的目的;

(2)用apply借用

xiaoyang.say.apply(xiaobai) // 小白有一只splider宠物

(3)用bind借用

xiaoyang.say.bind(xiaobai); // 不会输出任何结果

bind需要手动调用执行

xiaoyang.say.bind(xiaobai)()  // 小白有一只splider宠物


// 也可以将函数存到变量,等用到的时候执行
let xiaobaiSay=xiaoyang.say.bind(xiaobai);
xiaobaiSay();  // 小白有一只splider宠物


// 也可以直接给小白对象定义一个say属性,把借用来的函数用say存下来
xiaobai.say=xiaoyang.say.bind(xiaobai);
xiaobai.say();

如果直接赋值给小白对象,那么小白对象将永远有这个方法啦;所以bind可以用来对象或者函数间的继承;

 3 如何传参数

如果借用的函数,需要传参数进去;除了第一个参数是对象,后面需要传入参数;

仍然以上面小杨对象为例;

// 对象xiaoyang
let xiaoyang={
    name:'小杨',
    pet:'pig',
    say:function(petName,petAge){
        console.log(`${this.name}有一只${this.pet}宠物,名字叫${petName},今年${petAge}岁`)
    }
}

call、apply、bind的传参方式如下;

xiaoyang.say.call(xiaobai,'火玫瑰',2)
xiaoyang.say.apply(xiaobai,['火玫瑰',2])
xiaoyang.say.bind(xiaobai,'火玫瑰',2)()

输出结果都是一样的;apply的第二个参数传数组,但是say函数中,会自动给他展开,所以petName会对自动匹配数组第一个元素,petAge匹配第二个参数。

say函数中获取参数也可以利用arguments;如下效果是一样的

// 对象xiaoyang
let xiaoyang={
    name:'小杨',
    pet:'pig',
    say:function(){
        let [...arg]=arguments   // 将类数组arguments转为正常数组Array
        console.log(`${this.name}有一只${this.pet}宠物,名字叫${arg[0]},今年${arg[1]}岁`)
    }
}

4 手动实现上面三个方法

首先分析下原理,其实我们上面的目的就是想让我们的对象拥有一个他没有的函数;那么这么一想就理解了;可以将要借用的函数赋值给该对象,然后在内部执行即可;如下:

先以实现call函数为例 

// 在函数原型上定义一个callSelf函数
Function.prototype.callSelf = function (obj) {
  obj.fn = this;
  obj.fn();
  delete obj.fn;
}
// 以上面例子为例
// obj就是传入的小白对象;this就是say函数;然后直接执行say函数即可
// xiaoyang.say.callSelf(xiaobai,'火玫瑰',2)

注意,需要将fn函数给删除,不然小白对象就直接一直有fn这个函数了;占内存没必要。

如果传参数的话,实现如下;利用...解析类数组参数即可;

// 手动实现函数的call方法
Function.prototype.callSelf=function(){
    const [ctx, ...args] = arguments;   // ctx匹配第一个参数;args将剩余参数用数组组织起来
    ctx.fn=this;
    ctx.fn(...args);
    delete ctx.fn;
}
xiaoyang.say.callSelf(xiaobai,'火玫瑰',2)

apply和bind的实现如下:


// 手动实现函数的apply方法
Function.prototype.applySelf=function(){

    const [ctx, args] = arguments;  
    ctx.fn=this;
    ctx.fn(...args);
    delete ctx.fn;
}

// 手动实现函数的bind方法,借助apply
Function.prototype.bindSelf = function () {
  const [ctx, ...args] = arguments;
  const self = this; 
  return function () {
    self.apply(ctx, args);
  }
}

实现bind函数时,在内部不执行fn,而是将函数返回即可;同时不删除赋值给对象的函数fn;因为他需要后续调用执行;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨大大28

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值