每日一问---Class类中this绑定

class类中this绑定

类的方法内部如果含有this,默认指向类的实例,但是一些场景下使用,会导致this的指向偏离预期,所以需要绑定定义时候的this,也就是实例对象

如下

<!--html-->
<button id="btn">click</button>

<!--js-->
const btn = document.getElementById('btn');

class CheckThis {
  constructor(ele) {
    this.ele = ele;
    this.count = 0;
    this.ele.addEventListener('click', this.click);
  }
  click() {
    console.log(this); // DOM
    this.count++;
    console.log(this.count); // NaN
  }
}

const thisInstance = new CheckThis(btn);

在这里click方法中的this指的是dom节点而不是实例对象,

因为addEventListener()将this的指针设置为冒泡事件的DOM元素

相当于

var m = this.click;
this.ele.addEventListener('click', m) //此时m函数中this的指向创建事件的元素

再看一个例子

import React, { PureComponent } from 'react';
class Index extends PureComponent {
    testHandle(){
       console.log(this); // undefined
    };
    reder(){
        return (
            <Button onClick={this.testHandle}>click</Button>
        )
    }
}

React事件为合成事件,class并不会为方法自动绑定this到当前对象上,再由于class 内部是严格模式,所以 this 实际指向的是undefined,为避免这种this指向问题有几种方法来解决这种问题

1.使用箭头函数

直接在React元素中采用箭头函数

1
2
3
4
5
6
7
8
9
10
11
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle(){
console.log(this); // Index实例对象
};
reder(){
return (
<Button onClick={(event)=>this.testHandle(event)}>click</Button>
)
}
}

因为箭头函数中的this指向的是函数定义的对象,所以可以保证this总是指向当前组件的实例对象
优化点:直接在render方法中为元素事件定义事件的处理函数,每次render调用时,都会创建一个新的事件处理函数,带来额外的性能开销

2.组件方法

直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的this绑定到当前对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { PureComponent } from 'react';
class Index extends PureComponent {
constructor(props){
super(props);
this.state={}
this.testHandle = this.testHandle.bind(this);
}
testHandle(){
console.log(this); // Index实例对象
};
reder(){
return (
<Button onClick={this.testHandle}>click</Button>
)
}
}

这种方式的好处是每次render不会重新创建一个回调函数,没有额外的性能损失。但在构造函数中,为事件处理函数绑定this, 尤其是存在多个事件处理函数需要绑定时,这种模板式的代码还是会显得烦琐。而且对于函数传递参数来说不太方便

1
2
3
4
5
6
7
8
9
10
11
12
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle(params){
console.log(this,params); // Index实例对象, { test: '1' };
};
reder(){
const params = { test: '1' };
return(
<Button onClick={this.testHandle.bind(this,params)}>click</Button>
)
}
}

这种方式依然存在每次render都会创建一个函数的问题,但在需要为处理传递额外参数提供便利

3.属性初始化语法

使用ES 7的property initializers会自动为class中定义的方法绑定this

1
2
3
4
5
6
7
8
9
10
11
12
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle = (params)=>{
console.log(this,params); // Index实例对象, { test: '1' };
};
reder(){
const params = { test: '1' };
return(
<Button onClick={this.testHandle}>click</Button>
)
}
}

这种方式既不需要在构造函数中手动绑定this, 也不需要担心组件重复渲染导致的函数重复创建问题。但是, property initializers这个特性还处于试验阶段, 默认是不支持的,不过, 使用官方脚手架Create React App创建的项目默认是支持这个特性的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。

参考资料

引用 React+进阶之路

Recommended Posts