• js中改变this指向的call、apply、bind 方法使用


    前言: 

      由于js 中this的指向受函数运行环境的影响,指向经常改变,使得开发变得困难和模糊,所以在封装sdk,写一些复杂函数的时候经常会用到this 指向绑定,以避免出现不必要的问题,call、apply、bind基本都能实现这一功能,现对这三种方法使用总结一下:

    1、function.prototype.call()

          call 方法可以指定this 的指向(即函数执行时所在的的作用域),然后再指定的作用域中,执行函数

          call 方法的参数,应该是对象obj,如果参数为空或null,undefind,则默认传参全局对象 

    var obj = {};
    var f = function(){
    return this;
    };
    console.log(f() === window);  // this 指向window
    console.log(f.call(obj) === obj)  //改变this 指向 obj

       如果call 传参不是以上类型,则转化成对应的包装对象,然后传入方法。例如,5 转成number 实例,绑定f 内部 this

    var f = function () {
      return this;
    };
    
    f.call(5)
    // Number {[[PrimitiveValue]]: 5}

       call 可以接受多个参数,第一个参数是this 指向的对象,之后的是函数回调所需的入参

    function add(a, b) {
      return a + b;
    }
    
    add.call(this, 1, 2) // 3

    call方法的一个应用是调用对象的原生方法。

    var obj = {};
    obj.hasOwnProperty('toString') // false
    
    // 覆盖掉继承的 hasOwnProperty 方法
    obj.hasOwnProperty = function () {
      return true;
    };
    obj.hasOwnProperty('toString') // true
    
    Object.prototype.hasOwnProperty.call(obj, 'toString') // false

     上面代码中hasOwnProperty 是 obj 继承来的方法,用来判断对象是否包含自身特点(非继承)属性,但是hasOwnProperty 并不是保留字,如果被对象覆盖,会造成结果错误。

    call方法可以解决这个问题,它将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。

    hasOwnProperty  相关应用:https://www.cnblogs.com/weiqinl/p/8683207.html

    2、Function.prototype.apply()

        apply 和call 作用类似,也是改变this 指向,然后调用该函数,唯一区别是apply 接收数组作为函数执行时的参数

    func.apply(thisValue, [arg1, arg2, ...])

    apply方法的第一个参数也是this所要指向的那个对象,如果设为nullundefined,则等同于指定全局对象。

    第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。

    原函数的参数,在call方法中必须一个个添加,但是在apply方法中,必须以数组形式添加。

    function f(x, y){
      console.log(x + y);
    }
    
    f.call(null, 1, 1) // 2
    f.apply(null, [1, 1]) // 2

    利用这一特性,可以实现很多小功能

    比如,输出数组的最大值

     var a = [24,30,2,33,1]
     Math.max.apply(null,a)  //33

    将数组中的空值,转化成undefined,主要应用在数组遍历中,因为数组foreach 遍历会跳过空值,而不会跳过undefined

    var a = ['a',,'b'];
    Array.apply(null,a) //['a',undefind,'b']

    将类似于数组的对象转化成数组

    另外,利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。

    Array.prototype.slice.apply({0: 1, length: 1}) // [1]
    Array.prototype.slice.apply({0: 1}) // []
    Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
    Array.prototype.slice.apply({length: 1}) // [undefined]
    

    上面代码的apply方法的参数都是对象,但是返回结果都是数组,这就起到了将对象转成数组的目的。

    从上面代码可以看到,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键。

     

    3.Function.prototype.bind()

     bind 用于将函数体内的this绑定到某个对象,然后返回一个新函数

    var d = new Date();
    d.getTime() // 1481869925657
    
    var print = d.getTime;
    print() // Uncaught TypeError: this is not a Date object.

    报错是因为,d.getTime 赋值给 print 后,getTime 内部的this 指向方式变化,已经不再指向date 对象实例了

    解决方法

    var print = d.getTime.bind(d);
    print() // 1481869925657

    bind 接收的参数就是所要绑定的对象

    ar counter = {
      count: 0,
      inc: function () {
        this.count++;
      }
    };
    
    var func = counter.inc.bind(counter);
    func();
    counter.count // 1

    绑定到其他对象

    var counter = {
      count: 0,
      inc: function () {
        this.count++;
      }
    };
    
    var obj = {
      count: 100
    };
    var func = counter.inc.bind(obj);
    func();
    obj.count // 101

    bind 还可以接收更多的参数,将这些参数绑定到原函数的参数

    var add = function (x, y) {
      return x * this.m + y * this.n;
    }
    
    var obj = {
      m: 2,
      n: 2
    };
    
    var newAdd = add.bind(obj, 5);
    newAdd(5) // 20

    上面代码中,bind方法除了绑定this对象,还将add函数的第一个参数x绑定成5,然后返回一个新函数newAdd,这个函数只要再接受一个参数y就能运行了。

     

    总结:

    1. call 、 apply 、bind 均能改变this 指向

    2. apply 每次执行产生一个新函数,call、apply 不会

    3. call ,bind 接收多个参数绑定到函数,参数单一传入,apply 接收方式为数组

     

    更多详细资料:

      http://javascript.ruanyifeng.com/oop/this.html#toc7

  • 相关阅读:
    JasperReport笔记
    关于iReport5.6.0无法正常启动或者闪退或者JDK8不兼容的解决方案
    sublime text3 3176激活
    直播技术之编码和封装
    直播技术之推流和传输
    Quic协议剖析
    Glide Picasso和Fresco的对比
    MVP架构学习
    反向打印链表
    重建二叉树
  • 原文地址:https://www.cnblogs.com/nana-share/p/9469455.html
Copyright © 2020-2023  润新知