类中的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)
过程分析:
- this.changeWeather 找的是原型上的 changeWeather() 的⽅法
- 因为原型上的changeWeather() 的⽅法丢失了 this
- 所以使⽤ 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'))
- 此时类的原型对象上没有该方法,类的实例中有。