四、React学习笔记整理(类组件中this指向问题)

220 阅读3分钟

类中的this指向

问题描述

class Person{
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  speak(){
    console.info(this)
  }
}
let p = new Person('jack', 10);
// 通过实例调用speak方法,this就是person的实例
p.speak();

// 实例中的方法赋值给一个变量
let x = p.speak
// 通过变量直接调用,发现此时speak中的this为undefined
x()

思考:按理说this应该指向顶层的window对象,但是此时this为undefind
原因:由于class的内部,开启了局部严格模式use strict,所以this不会指向window所以undefined
验证:在class外部进行方法声明及调用

<script>
    function demo() {
      //此处this指向window对象,因为demo方法不是在类中,只有在类中的方法才会开启严格模式,所以类中方法的this是undefined。
      console.log(this);
    }
    demo()
</script>

总结:在类中,由于开启了局部严格模式,所以在类中的方法无法获取this,因此方法中的this不会指向window

react中类组件this分析

 // 1.天气组件
class Weather extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      isHot: true
    }
  }
  // 这样声明的方法,是在实例对象的原型对象上。
  changeWeather(){
    // 在类中,方法会默认开启严格模式,就会导致方法中this无法指向实例对象。此处this是undefind
    console.log(this);
  }
  render() {
    // render函数是被组件实例调用的,因此render函数中的this指向当前组件
    console.log('render this', this);
    const{isHot} = this.state
    return (
      // 这里调用函数时,不能加(),否则会被当做表达式立即执行
      // 此处的this是当前组件发起的
      <div id="title" onClick={this.changeWeather}>
          今天天气很{isHot === true ? '炎热' : '凉爽'}
      </div>
    );
  }
}
ReactDOM.render(<Weather/>, document.getElementById('test'))

解决类方法中的this指向问题

方法一:使用bind改变this指向

 // 1.天气组件
        class Weather extends React.Component{
          constructor(props){
            super(props);
            this.state = {
              isHot: true
            }
            // 写法一:bind改变this指向(将this.changeWeather绑定到实例对象上)
            // 写法二:在onClick调用时使用onClick={this.changeWeather.bind(this)}进行绑定
            this.changeWeather = this.changeWeather.bind(this)
          }

          changeWeather(){
            console.log(this);
          }
          render() {
            console.log('render this', this);
            const{isHot} = this.state
            return (
              <div id="title" onClick={this.changeWeather}>
                  今天天气很{isHot === true ? '炎热' : '凉爽'}
              </div>
            );
          }
        }
        ReactDOM.render(<Weather/>, document.getElementById('test'))
  • 此时类的不止原型对象上有该方法,类的实例中也有changeWeather方法
  • 当类实例与类原型对象都有相同的方法时,会优先调用实例对象上的。
this.changeWeather = this.changeWeather.bind(this)

过程分析:

  1. this.changeWeather 找的是原型上的 changeWeather() 的⽅法
  2. 因为原型上的changeWeather() 的⽅法丢失了 this
  3. 所以使⽤ bind ⽅法来改变原型上的changeWeather() 的⽅法中的this指向     bind 可以改变函数中 this 的指向, 传什么值, this 指向就被修改成什么, 但是这个 bind 并不是修改的原函数, ⽽是⽣成了⼀个新函数。
        bind 我们将这个新⽣成的函数, 赋值给 = 左边的 this.changeWeather , 这个this.changeWeather 是实例上的⽅法。
        总结来说, 就是先找到类原型上的 changeWeather ⽅法, 然后使⽤ bind 重置changeWeather ⽅法的 this 指向, 之后将得到的新函数, 给到实例的changeWeather 属性

方法二:使用箭头函数

 // 1.天气组件
        class Weather extends React.Component{
          constructor(props){
            super(props);
            this.state = {
              isHot: true
            }
          }

          changeWeather(){
            console.log(this);
          }
          render() {
            console.log('render this', this);
            const{isHot} = this.state
            return (
              <div id="title" onClick={() => this.changeWeather}>
                  今天天气很{isHot === true ? '炎热' : '凉爽'}
              </div>
            );
          }
        }
        ReactDOM.render(<Weather/>, document.getElementById('test'))
  • 此时类的原型对象上有该方法,类的实例中没有。 方法三:class 的实例方法【推荐】
 // 1.天气组件
        class Weather extends React.Component{
          constructor(props){
            super(props);
            this.state = {
              isHot: true
            }
          }

          changeWeather = () => {
            console.log(this);
          }
          render() {
            console.log('render this', this);
            const{isHot} = this.state
            return (
              <div id="title" onClick={this.changeWeather}>
                  今天天气很{isHot === true ? '炎热' : '凉爽'}
              </div>
            );
          }
        }
        ReactDOM.render(<Weather/>, document.getElementById('test'))
  • 此时类的原型对象上没有该方法,类的实例中有。