class中this的指向

基本原则

  • class的本质是function。它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法
  • 类中定义的方法,都放在了类的原型上,供实例对象调用
  • 类中可以直接写赋值语句,写一个a = 1,就是给实例对象添加一个属性,名为a,值为1
  • 构造器中的this是 类的实例对象
class Student {
  study () {
    console.log(this)
  }
}
  • 通过Student实例对象调用study方法时,study中的this就是Student实例对象

用一个React的demo来分析this的指向问题

class Weather extends React.Component{	
  constructor (props) {
    super(props)
    this.state = { isHot: false }
  }
  render () {
    const { isHot } = this.state
    return <h1 onClick={ this.changeWeather }>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
  }
  changeWeather () {
    const isHot = this.state.isHot
    this.setState({ isHot:!isHot })
    console.log(this);
  }
}
ReactDOM.render(<Weather/>,document.getElementById('test'))

实现效果:点击h1标签中的内容,能实现“凉爽”与“炎热”的切换

这种写法是错误的,点击h1内容时,会报错:Uncaught TypeError: Cannot read properties of undefined (reading ‘state’)

这是因为

<h1 onClick={ this.changeWeather }>今天天气很{isHot ? '炎热' : '凉爽'}</h1>

由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用,里面的this应该是全局window。而类中的方法已经在局部开启了严格模式,所以里面的this就会指向undefined,undefined.state就会报错

就是类似于一个这样的demo

const p1 = new Person('tom',18)
p1.study() //通过实例调用study方法
const x = p1.study
x() // 直接调用

解决方案一:bind

在构造器里写一句

this.changeWeather = this.changeWeather.bind(this)

分析这句话,它是一个赋值语句,我们就从右边开始分析:this.changeWeather.bind(this)。这句话写在构造器里,构造器里的this是实例对象,我们在class里实现的changeWeather方法放在实例对象的原型上,this顺着原型链向上查找就找到了changeWeather方法(this.changeWeather的由来)

bind能做两件事:

  1. 帮你生成一个新的函数
  2. 帮你改了函数里的this

由于构造器里的this就是Weather实例对象
this.changeWeather.bind(this) 它执行完后,你手里就有了一个新的函数,这个函数里的this已经成功变成了Weather实例对象

然后this.changeWeather = this.changeWeather.bind(this)
你把这个函数放到了实例对象的自身,还给这个函数起了一个名字,叫做changeWeather。这时候你的实例对象自身就多了一个方法,叫做changeWeather

也就是说:拿着原型上的changeWeather,生成新的、修改过函数内部this指向的changeWeather,并挂在自身。

解决方案二:赋值语句+箭头函数

class Weather extends React.Component{
  state = { isHot: false }
  render () {
    const { isHot } = this.state
    return <h1 onClick={ this.changeWeather }>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
  }
  changeWeather = () => {
    const isHot = this.state.isHot
    this.setState({ isHot: !isHot })
  }
}
ReactDOM.render(<Weather/>,document.getElementById('test'))
  • 把类中的方法用“赋值语句”来写,这个方法就挂在实例对象自身了,而不是挂在其原型上
  • 使用箭头函数,函数体中的this就是其外部作用域的this。那里的this就是组件实例对象
  • 构造器也可以省略不写了,实际上完全没必要写
箭头函数补充

菜鸟教程里有一句话说得特别好:箭头函数体中的this对象,是定义函数时的对象,而不是使用函数时的对象

function fn(){
  setTimeout(()=>{
    // 定义时,this 绑定的是 fn 中的 this 对象
    console.log(this.a);
  },0)
}
var a = 20;
// fn 的 this 对象为 {a: 18}
fn.call({a: 18});  // 18
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值