【call、apply、bind简介】区别及应用场景

已被阅读 1245 次 | 文章分类:日常随笔 | 2022-03-29 00:11

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

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可以用来对象或者函数间的继承

/net/upload/image/20220329/e78d5d81c76a4750aa3f16e8e80cb008.png

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;因为他需要后续调用执行;

QQ:3410192267 | 技术支持 微信:popstarqqsmall

Copyright ©2017 xiaobaigis.com . 版权所有 鲁ICP备17027716号