当前位置: 首页 > article >正文

call、bind、apply的区别

1.作用

2.使用方法

2.1 apply

2.2 call

 2.3 bind

3.区别

3.1 传参区别

3.1.1 apply

3.1.2 call

3.1.3 bind

3.2 调用区别

3.2.1 apply和call

3.2.2 bind

4.相同

5.应用场景

5.1 apply和call

 5.2 bind

6.注意事项

6.1 连续使用多次bind

6.2 连续使用多次call或者apply


1.作用

call、bind、apply的作用都是改变函数执行时的上下文,也就是修改函数的this指向。

    let name = '于家宝'
    let obj = {
      name: 'yujiabao',
      say: function () {
        console.log(this.name)
      }
    }
    obj.say()  // yujiabao
    setTimeout(obj.say, 0)  // 于家宝

从上面代码来看,say方法正常情况下由obj调用,this指向obj,输出是yujiabao。

但是放在setTimeout中,在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,这时this指向window,所以输出于家宝。

我们实际上需要的是this指向obj,这时候就需要去修改this的指向了。

    setTimeout(obj.say.bind(obj), 1000)  // yujiabao

2.使用方法

2.1 apply

func.apply(thisArg,argsArray)

作用:修改函数的this指向和往函数传递参数,并调用该函数,相当于调用函数的时候临时修改一下this指向。

  • thisArg:func函数的this指向。
  • argsArray:传入func函数的参数,是一个数组,可以忽略。

返回值:无。

    let name = '于家宝'
    let obj = {
      name: 'yujiabao',
      say: function (a, b) {
        console.log(`${this.name}今年${a + b}岁`)
      }
    }
    // 修改this指向为window并调用该函数
    obj.say.apply(this, [10, 8]) // 于家宝今年18岁

2.2 call

基本和apply相同用法,只是接收参数的方式不一样。

func.call(thisArg,arg1,arg2...)

作用:修改函数的this指向和往函数传递参数,并调用该函数,相当于调用函数的时候临时修改一下this指向。

参数:

  • thisArg:func函数的this指向。
  • arg1,arg2...:传入func函数的参数,可以多个,可以忽略。

返回值:无。

    let name = '于家宝'
    let obj = {
      name: 'yujiabao',
      say: function (a, b) {
        console.log(`${this.name}今年${a + b}岁`)
      }
    }
    // 修改this指向为window并调用该函数
    obj.say.call(this, 10, 8) // 于家宝今年18岁

 2.3 bind

func.bind(thisArg,arg1,arg2...)

作用:修改函数的this指向和往函数传递参数,但是不会调用该函数,而是返回一个新的函数,这就是创建一个永久修改this指向的函数。

参数:

  • thisArg:创建的新函数的this指向。
  • arg1,arg2...:传入func函数的参数,可以多个,可以忽略。

返回值:一个修改了this指向的新函数。

    let name = '于家宝'
    let obj = {
      name: 'yujiabao',
      say: function (a, b) {
        console.log(`${this.name}今年${a + b}岁`)
      }
    }
    // 修改this指向为window,但是不会直接调用而是返回一个新函数
    let newSay = obj.say.bind(this, 10, 8)
    newSay() // 于家宝今年18岁

3.区别

3.1 传参区别

3.1.1 apply

apply的传参是将所有参数封装在一个数组中传给函数。

    obj.say.apply(this, [10, 8])
3.1.2 call

call的传参是一个一个单独往函数中去传参。

    obj.say.call(this, 10, 8)
3.1.3 bind

bind的传参跟call类似,也是一个一个单独的往函数中传参,但是可以分批传参。 

    let name = '于家宝'
    let obj = {
      name: 'yujiabao',
      say: function (a, b) {
        console.log(`${this.name}今年${a + b}岁`)
      }
    }
    // 先往新函数传一个固定参数 10
    let newSay = obj.say.bind(this, 10)

    // 现在就可以传后面的参数
    newSay(8) // 于家宝今年18岁
    newSay(9) // 于家宝今年19岁

3.2 调用区别

3.2.1 apply和call

call 和 apply 方法修改完函数的this指向后会立即调用该函数,相当于调用函数的时候临时修改一下this指向。

    // 通过 apply 立即执行
    obj.say.apply(this, [10, 8])
    // 通过 call 立即执行
    obj.say.call(this, 10, 8)
3.2.2 bind

bind方法修改完函数的this指向后不会调用该函数,而是将其返回为一个新的函数,我们通过调用这个新的函数去实现修改this指向的效果。

    let newSay = obj.say.bind(this, 10)
    newSay(8) // 于家宝今年18岁

4.相同

都运用于修改函数的this指向,如果不传入第一个参数或者传入undefined、null,this指向为全局对象。

5.应用场景

5.1 apply和call

apply和call都是临时修改函数的this指向,当一个对象没有某个方法,而其他对象有这个方法,就可以借助apply或者call去临时使用这个方法。

    let obj1 = {
      name: 'yujiabao',
      say: function () {
        console.log(`我叫${this.name}`)
      }
    }
    let obj2 = {
      name: '于家宝'
    }

    // 让obj2使用say方法
    obj1.say.call(obj2) // 我叫于家宝

apply相比于call,如果函数参数数量不确定,可以使用arguments, arguments是一个伪数组,这个时候apply就会更好用一点。

再举个例子:

定义一个log方法去实现console.log()的功能。

最开始的写法:

    function log(msg) {
      console.log(msg)
    }
    log(1) //1
    log(1, 2) //1

上面的方法可以实现基本需求,但是当传入的参数不固定的时候,方法就失效了,这时候就可以考虑使用apply或者call方法,因为参数是不固定的,所以这里使用apply。

    function log() {
      console.log.apply(console, arguments)
      // 不能用 console.log(arguments),因为arguments是数组,这样就会打印出来一个数组 [1,2]
      // 所以使用apply方法,就相当于 console.log() 然后传入参数 1 ,2
    }
    log(1) //1
    log(1, 2) //1 2

如果想在每个log信息之前加个(于家宝)前缀,比如:

    log(1,2) // (于家宝) 1 2

 就相当于log('于家宝',1,2),而arguments是一个伪数组,我们可以将其转换为数组,然后使用数组的方法在前面加上‘于家宝’:

    function log() {
      let args = [].slice.call(arguments)
      args.unshift('于家宝')
      console.log.apply(console, args)
    }
    log(1) // 于家宝 1
    log(1, 2) // 于家宝 1 2

 5.2 bind

因为bind是返回一个新的函数而不是立即调用,所以可以用于某些条件触发后调用的回调函数。如果用call或者apply就直接触发了。

    var button = document.getElementById('myButton')
    var person = {
      name: 'John',
      handleClick: function () {
        console.log('Button clicked by' + this.name)
      }
    }

    button.addEventListener('click', person.handleClick.bind(person))

6.注意事项

6.1 连续使用多次bind

    let obj = {
      name: 'yujiabao',
      say: function () {
        console.log(`我叫${this.name}`)
      }
    }
    let name = '于家宝'
    let newObj = obj.say.bind(this).bind(obj)
    newObj() // ?

上面代码输入的结果:于家宝。

而不是预想中的yujiabao。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

6.2 连续使用多次call或者apply

会报错,用完一次以后又不是返回个函数哪来的第二次调用。


http://www.kler.cn/a/451362.html

相关文章:

  • 深入解析:Python中的决策树与随机森林
  • 京东零售数据可视化平台产品实践与思考
  • JavaScript中的Set、Map、WeakSet和WeakMap
  • Linux 基本使用和程序部署
  • Day13 用Excel表体验梯度下降法
  • 鸿蒙app封装 axios post请求失败问题
  • Python OCR 文字识别
  • 基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(二)
  • 外包干了两年,技术退步明显。。。。
  • 时钟芯片入门指南:从原理到实践
  • 作业帮基于 Apache DolphinScheduler 3_0_0 的缺陷修复与优化
  • HarmonyOS Next 应用元服务开发-分布式数据对象迁移数据文件资产迁移
  • 力扣-图论-18【算法学习day.68】
  • 掌握 Ansys ACP 中的参考方向:简化复杂的复合材料设计
  • 怎么设置电脑密码?Windows和Mac设置密码的方法
  • RPC入门教学(一) ———— RPC介绍与protobuf的介绍与使用
  • QT--信号与槽机制
  • k8s dashboard可视化操作界面的安装
  • 利用Converge许可分析提高软件使用效率
  • windows安装java
  • 深度学习day5|用pytoch实现运动鞋识别
  • 【人工智能离散数学基础】——深入详解图论:基础图结构及算法,应用于图神经网络等
  • 微信小程序中momentjs无法切换中文问题处理
  • 鸿蒙(HarmonyOS)原生AI能力之文本识别
  • openssl交叉编译(这次基本上正规了)
  • QT的前景与互联网岗位发展