• 技术文章 >web前端 >js教程

    JS 中几种处理’this’指向的方式

    尚2020-06-18 17:18:03转载720

    我喜欢在JS中更改函数执行上下文的指向,也称为 this 指向。

    例如,咱们可以在类数组对象上使用数组方法:

    const reduce = Array.prototype.reduce;
    
    function sumArgs() {
      return reduce.call(arguments, (sum, value) => {
        return sum += value;
      });
    }
    
    sumArgs(1, 2, 3); // => 6

    另一方面,this 很难把握。

    咱们经常会发现自己用的 this 指向不正确。下面的教你如何简单地将 this 绑定到所需的值。

    在开始之前,我需要一个辅助函数execute(func),它仅执行作为参数提供的函数。

    function execute(func) {
      return func();
    }
    
    execute(function() { return 10 }); // => 10

    现在,继续理解围绕this错误的本质:方法分离。

    1.方法分离问题

    假设有一个类Person包含字段firstNamelastName。此外,它还有一个方法getFullName(),该方法返回此人的全名。如下所示:

    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    
      this.getFullName = function() {
        this === agent; // => true
        return `${this.firstName} ${this.lastName}`;
      }
    }
    
    const agent = new Person('前端', '小智');
    agent.getFullName(); // => '前端 小智'

    可以看到Person函数作为构造函数被调用:new Person('前端', '小智')。函数内部的 this 表示新创建的实例。

    getfullname()返回此人的全名:'前端 小智'。正如预期的那样,getFullName()方法内的 this 等于agent

    如果辅助函数执行agent.getFullName方法会发生什么:

    execute(agent.getFullName); // => 'undefined undefined'

    执行结果不正确:'undefined undefined',这是 this 指向不正确导致的问题。

    现在在getFullName() 方法中,this的值是全局对象(浏览器环境中的 window )。this 等于 window${window.firstName} ${window.lastName} 执行结果是 'undefined undefined'

    发生这种情况是因为在调用execute(agent.getFullName)时该方法与对象分离。基本上发生的只是常规函数调用(不是方法调用):

    execute(agent.getFullName); // => 'undefined undefined'
    
    // 等价于:
    
    const getFullNameSeparated = agent.getFullName;
    execute(getFullNameSeparated); // => 'undefined undefined'

    这个就是所谓的方法从它的对象中分离出来,当方法被分离,然后执行时,this 与原始对象没有连接。

    为了确保方法内部的this指向正确的对象,必须这样做

    1. 以属性访问器的形式执行方法:agent.getFullName()

    2. 或者静态地将this绑定到包含的对象(使用箭头函数、.bind()方法等)

    方法分离问题,以及由此导致this指向不正确,一般会在下面的几种情况中出现:

    回调

    // `methodHandler()`中的`this`是全局对象
    setTimeout(object.handlerMethod, 1000);

    在设置事件处理程序时

    // React: `methodHandler()`中的`this`是全局对象
    <button onClick={object.handlerMethod}>
      Click me
    </button>

    接着介绍一些有用的方法,即如果方法与对象分离,如何使this指向所需的对象。

    2. 关闭上下文

    保持this指向类实例的最简单方法是使用一个额外的变量self:

    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    
      const self = this;
    
      this.getFullName = function() {
        self === agent; // => true
        return `${self.firstName} ${self.lastName}`;
      }
    }
    
    const agent = new Person('前端', '小智');
    
    agent.getFullName();        // => '前端 小智'
    execute(agent.getFullName); // => '前端 小智'

    getFullName()静态地关闭self变量,有效地对this进行手动绑定。

    现在,当调用execute(agent.getFullName)时,一切工作正常,因为getFullName()方法内 this 总是指向正确的值。

    3.使用箭头函数

    有没有办法在没有附加变量的情况下静态绑定this?是的,这正是箭头函数的作用。

    使用箭头函数重构Person:

    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    
      this.getFullName = () => `${this.firstName} ${this.lastName}`;
    }
    
    const agent = new Person('前端', '小智');
    
    agent.getFullName();        // => '前端 小智'
    execute(agent.getFullName); // => '前端 小智'

    箭头函数以词法方式绑定this。简单来说,它使用来自其定义的外部函数this的值。

    建议在需要使用外部函数上下文的所有情况下都使用箭头函数。

    4. 绑定上下文

    现在让咱们更进一步,使用ES6中的类重构Person

    class Person {
      constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
      }
    
      getFullName() {
        return `${this.firstName} ${this.lastName}`;
      }
    }
    
    const agent = new Person('前端', '小智');
    
    agent.getFullName();        // => '前端 小智'
    execute(agent.getFullName); // => 'undefined undefined'

    不幸的是,即使使用新的类语法,execute(agent.getFullName)仍然返回“undefined undefined”

    在类的情况下,使用附加的变量self或箭头函数来修复this的指向是行不通的。

    但是有一个涉及bind()方法的技巧,它将方法的上下文绑定到构造函数中:

    class Person {
      constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    
        this.getFullName = this.getFullName.bind(this);
      }
    
      getFullName() {
        return `${this.firstName} ${this.lastName}`;
      }
    }
    
    const agent = new Person('前端', '小智');
    
    agent.getFullName();        // => '前端 小智'
    execute(agent.getFullName); // => '前端 小智'

    构造函数中的this.getFullName = this.getFullName.bind(this)将方法getFullName()绑定到类实例。

    execute(agent.getFullName) 按预期工作,返回'前端 小智'

    5. 胖箭头方法

    bind 方式有点太过冗长,咱们可以使用胖箭头的方式:

    class Person {
      constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
      }
    
      getFullName = () => {
        return `${this.firstName} ${this.lastName}`;
      }
    }
    
    const agent = new Person('前端', '小智');
    
    agent.getFullName();        // => '前端 小智'
    execute(agent.getFullName); // => '前端 小智'

    胖箭头方法getFullName =() =>{…}绑定到类实例,即使将方法与其对象分离。

    这种方法是在类中绑定this的最有效和最简洁的方法。

    6. 总结

    与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this

    在类中,可以使用bind()方法手动绑定构造函数中的类方法。当然如果你不用使用 bind 这种冗长方式,也可以使用简洁方便的胖箭头表示方法。

    更多JavaScript知识请关注PHP中文网JavaScript视频教程栏目

    以上就是JS 中几种处理’this’指向的方式的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:CSDN,如有侵犯,请联系admin@php.cn删除
    专题推荐:JS this
    上一篇:如何检测一个函数是否是JavaScript原生函数 下一篇:js中闭包的概念
    大前端线上培训班

    相关文章推荐

    • JS中this究竟指向什么?• JavaScript中this绑定方式总结• java中this关键字的四种用法是什么• JS干货分享—-this指向问题

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网