• js中call、apply和bind:



    一、区别:

    call、apply、bind相同点:都是改变this的指向,传入的第一个参数都是绑定this的指向,在非严格模式中,如果第一个参数是nul或者undefined,会把全局对象(浏览器是window)作为this的值,要注意的是,在严格模式中,null 就是 null,undefined 就是 undefined

    call和apply唯一的区别是:call传入的是参数列表,apply传入的是数组,也可以是类数组

    bind和call、apply的区别: bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
    值得注意:当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效 (new调用的优先级 > bind调用)

    在这里插入图片描述

    二、案例:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    三、实现:
    【1】call实现

    对象context想调用一个它没有的方法f 怎么办呢?f.call(context) 通过call来借用方法f ,怎么做到的呢

    1. 对象context添加f方法
    2. 对象context执行f方法
    Function.prototype.myCall = function(context, ...arg) {
        // 如果第一个参数传入的是undefined和null,context为window对象
        context = context || window;  
         
        // 为context对象添加函数bar
        context.fn = this;   // this:bar,this指向调用myCall的bar  
     
        // context对象执行函数bar,并返回结果
        return  context.fn(...arg); 
    }
     
    // 测试一下
    var value = 2;
     
    var obj = {
        value: 1
    }
    function bar(name, age) {
        console.log(this.value);
        return {
            value: this.value,
            name: name,
            age: age
        }
    }
    
    bar.myCall(null); // 2  this指向window
     
    console.log(bar.myCall(obj, 'kevin', 18)); //1  this指向obj  Object { value: 1,name: 'kevin',age: 18}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    【2】apply实现

    apply和call唯一的区别是:call传入的是参数列表,apply传入的是数组,也可以是类数组

    Function.prototype.myApply = function(context, arg) {
        // 如果第一个参数传入的是undefined和null,context为window对象
        context = context || window;  
         
        // context对象添加函数bar
        context.fn = this;   // this:bar,this指向调用myCall的函数bar  
     
        // context对象执行函数bar,并返回结果
        let result = null;
        if (!arg) { // 没有传入数组
            result = context.fn();
        }else{      // 传入了参数数组
            result = context.fn(...arg);
        } 
        return result;
    }
     
    // 测试一下
    var value = 2;
     
    var obj = {
        value: 1
    }
    function bar(name, age) {
        console.log(this.value);
        return {
            value: this.value,
            name: name,
            age: age
        }
    }
     
    bar.myApply(null); // 2 
    console.log(bar.myApply(obj, ['kevin', 18])); // 1   传入的是数组['kevin', 18]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    【3】bind实现

    bind和call、apply的区别: bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
    值得注意:当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效 (new调用的优先级 > bind调用)
    bind实现最为复杂,因为经过bind绑定过的函数,既可以被当作普通函数调用,又可以被当作构造函数调用

    Function.prototype.myBind = function (context, ...args){
        // 如果第一个参数传入的是undefined和null,context为window对象
        context = context || window;
     
        // context对象添加函数Person
        context.fn = this;     // this:Person,context.fn:Person,_this:Person
        let _this = this;
         
        // bind返回的函数 
        const result = function (...innerArgs) { 
            if (this instanceof _this ) { // this:a (new出来的实例对象) ,  _this:Person
                // 为实例对象a添加Person方法
                this.fn = _this;
                // 实例对象a执行Person方法
                this.fn(...[...args,...innerArgs]);
            }else{
                // 普通函数被调用
                context.fn(...[...args,...innerArgs]);
            }
        }
         
        result.prototype = Object.create(this.prototype);  // 为什加这一句?看原型图下面会解释
        return result;
    }
     
    // 测试
    // function Person(name, age) {
    //   console.log(name); //'我是第一次参数传进来的name被args接收'
    //   console.log(age); //'我是第二次参数传进来的age被innerArgs接收'
    //   console.log(this); //构造函数this指向实例对象
    // }
    // // 构造函数原型的方法
    // Person.prototype.say = function() {
    //   console.log(123);
    // }
     
    // let obj = {
    //   objName: '我是obj传进来的name',
    //   objAge: '我是obj传进来的age'
    // }
     
    // // bind 返回的函数 作为构造函数调用
    // let bindFun = Person.myBind(obj, '我是第一次参数传进来的name被args接收') // this:obj
    // let a = new bindFun('我是第二次参数传进来的age被innerArgs接收')               // this:a
    // a.say() //123
     
    // 测试
    let obj = {
      objName: '我是obj传进来的name',
      objAge: '我是obj传进来的age'
    }
     
    // 普通函数
    function normalFun(name, age) {
      console.log(name);          //'我是第一次参数传进来的name'
      console.log(age);           //'我是第二次参数传进来的age'
      console.log(this === obj);  // true
      console.log(this.objName);  //'我是obj传进来的name'
      console.log(this.objAge);   //'我是obj传进来的age'
    }
     
    // bind 返回的函数 作为普通函数调用
    let bindFun = normalFun.myBind(obj, '我是第一次参数传进来的name被args接收'); // this指向obj 
    bindFun('我是第二次参数传进来的age被innerArgs接收');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    nginx负载转发源请求http/https:X-Forwarded-Proto及nginx中的转发报头
    【MyBatisⅡ】动态 SQL
    ADC 抗体偶联药物通过连接子 linker 连接而成
    云计算在智能制造中的应用与前景
    深度学习 - RNN训练过程推演
    DNS和ICMP协议
    让酒酿得更明白,国台智能酿造标准体系重磅发布
    es elasticsearch 八 mapping 映射 、复杂数据类型
    80.每日一练:移除元素(力扣)
    Day6:面试必考选择题
  • 原文地址:https://blog.csdn.net/weixin_53791978/article/details/132671535