• call、apply 以及 bind 的区别和用法


    call、apply、bind

    call和apply共同点

    • 共同点:改变函数执行时的上下文,将一个对象的方法交给另一个对象来执行,并且是立即执行的
    • call和apply的对象,必须是一个函数Function

    call和apply区别

    call的写法

    Function.call(obj, [param1[, param2[, ...[, paramN]]]])

    需要注意以下几点:

    • 调用call的对象,必须是个函数Function
    • call的第一个参数,是一个对象,Function的调用者,将会指向这个对象。如果不传,则默认为全局对象window
    • 第二个参数开始,可以接收任意个参数,每个参数会映射到相应位置的Function的参数上。
    • 但是如果将所有的参数作为数组传入,他们会作为一个整体映射到Function对应的第一个参数上,之后参数都为空
    function func(a,b,c) {}
    func.call(obj, 1,2,3) // func接收到的参数为1,2,3
    func.call(obj, [1,2,3]) // func接收到的参数为[1,2,3], undefined, undefined 
    
    • 1
    • 2
    • 3

    apply的写法

    Function.apply(obj[, argArray])

    需要注意的是:

    • 它的调用者必须是函数Function,并且只接受两个参数,第一个参数的规则与call一致
    • 第二个参数,必须是数组或者类数组,他们会被转换成类数组,传入到Function中,并且会被映射到Function对应的参数上,
    func.apply(obj, [1,2,3]) // func接收到的参数是1,2,3
    func.apply(obj, {0:1, 1:2, 2:3, length: 3}) // func接收到的参数是1,2,3 
    
    • 1
    • 2

    什么是类数组

    • 具备与数组特征类似的对象
    • 类数组无法使用forEach、splice、push等数组原型链上的方法

    call和apply的用途

    call的使用场景

    • 对象的继承
    function superClass() {this.a = 1this.print = function() {console.log(this.a)}
    }
    function subClass() {superClass.call(this)this.print()
    }
    subClass() // 1 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 借用方法* 类数组,如果想使用Array原型链上的方法* let demoNodes = Array.prototype.slice.call(document.getElementsByTagName("*"))

    apply 的用法

    • Math.max,用来获取数组中最大的一项* let max = Math.max.apply(null, array)
    • 实现两个数组合并
    let arr1 = [1, 2, 3]
    let arr2 = [4, 5, 6]
    Array.prototype.push.apply(arr1, arr2)
    console.log(arr1) // [1, 2, 3, 4, 5, 6] 
    
    • 1
    • 2
    • 3
    • 4

    bind的使用

    bind()方法创建一个新的函数,在调用时设置this关键字为提供的值,并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项

    Function.bind(thisArg, arg1, arg2])

    • bind方法与apply、call比较类似,也能改变函数体内的this指向,不同的是,bind方法的返回值是函数,并且需要稍后调用,才会执行。而apply和call则是立即调用
    • 如果bind的第一个参数是null或者undefined,this就指向全局对象window
    function add (a, b) {return a + b;
    }
    function sub (a, b) {return a - b;
    }
    add.bind(sub, 5, 3); // 这时,并不会返回 8
    add.bind(sub, 5, 3)(); // 调用后,返回 8 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    总结

    • call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。它们在参数上的写法略有区别。* bind 也能改变对象的执行上下文,它与 call 和 apply 不同的是,返回值是一个函数,并且需要稍后再调用一下,才会执行。bind的模拟实现
      =========

    bind

    bind()方法创建一个新函数,当这个新函数被调用时,bind()的第一个参数将作为它运行时的this,之后的一序列参数将会在传递的实参钱传入作为它的参数

    function fn(a, b, c) {return a + b + c;
    }
    var _fn = fn.bind(null, 10);
    var ans = _fn(20, 30); // 60 
    
    • 1
    • 2
    • 3
    • 4

    它的特点:

    1.返回一个函数;
    2.可以传入参数

    实现bind最终代码

    Function.prototype.bind1 = function(context) {if (typeof this !== 'function') {throw new Error('Function.prototype.bind --what is trying to be bound is not callable')}var self = thisvar args = Array.prototype.slice.call(arguments, 1)var fNOP = function () {}var fBound = function() {var bindArgs = Array.prototype.slice.call(arguments) // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值// 以上面的是 demo 为例,如果改成 `this instanceof fBound ? null : context`,实例只是一个空对象,将 null 改成 this ,实例会具有 habit 属性// 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 contextreturn self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs))}fNOP.prototype = this.prototypefBound.prototype = new fNOP()return fBound
    } 
    
    • 1
    • 2
  • 相关阅读:
    Json序列化与反序列化导致多线程运行速度和单线程运行速度一致问题
    三、工厂方法模式
    Ajax基础实例,看了直接掌握学会!
    Yolov8-pose关键点检测:模型轻量化创新 | OREPA结合c2f,节省70%的显存!训练速度提高2倍! | CVPR2022
    Hbase Java API原理介绍
    SpringBoot 还用 if 校验参数?老司机都是这么玩的!
    landsat 卫星影像的常见问题(去云、是否进行几何和大气校正以及数据产品的处理级别)
    EFLK日志平台(filebeat-->kafka-->logstash-->es-->kiabana)
    JavaScript-怪癖检测
    微信小程序 camera组件实现自定义界面的扫码功能
  • 原文地址:https://blog.csdn.net/web2022050903/article/details/126054681