一,this指向(React事件处理函数为什么需要手动绑定this)
this指的是函数运行时所在的环境对象
普通函数
普通函数的this指向的是调用它的对象,而且是离谁近指向谁,可以通过call,bind,apply修改this指向。
- 普通模式下,顶级作用域中,函数默认绑定到window上,this指向的是window
- 严格模式下,顶级作用域中,函数默认是未定义的,this执行undefined
箭头函数
箭头函数的this指向是定义它时所在作用域的this指向,定义的时候就已经确定了,不会根据谁调用而改变,不能通过call,bind,apply修改this指向。
非严格模式下
var obj = {
innerObj: {
foo: function() {
console.log(this);
}
}
}
obj.innerObj.foo();// {foo: ƒ}
var temp = obj.innerObj.foo;
temp();//Window {window: Window, self: Window, …}
严格模式下
'use strict'
var obj = {
innerObj: {
foo: function() {
console.log(this);
}
}
}
obj.innerObj.foo();// {foo: ƒ}
var temp = obj.innerObj.foo;
temp();//undefined
当严格模式下将函数赋值给一个中间变量时会造成this指向丢失
import react from "react";
class News extends react.Component {
constructor(props){
super(props);
this.state = {
name: "melinda"
}
}
handleClick(){
console.log(this,this.setState({name: 'melinda啦啦啦啦'}))
}
render(){
return (
<div>
<button onClick={this.handleClick}>修改name</button>
<p>{this.state.name}</p>
</div>
)
}
}
export default News;
会报错TypeError: Cannot read properties of undefined (reading 'setState')
结论:react使用babel将JSX和ES6转ES5的时候,默认转化之后是严格模式,此时window下面的onClick事件就相当于一个中间变量,执行onclick里面的函数时,里面的this就会指向undefined,要让this指向当前实例就需要通过箭头函数或者bind改变this的指向。
二,绑定this的四种方法
1,在构造函数中使用bind绑定this
2,在调用的时候使用bind绑定this
3,使用属性初始化器语法绑定this(使用箭头函数声明)
4,在调用的时候使用使用箭头函数绑定this
import react from "react";
class News extends react.Component {
constructor(props){
super(props);
this.state = {
name: "melinda"
}
//方法1
this.handleClick1 = this.handleClick1.bind(this);
}
handleClick1(){
console.log(111,this,this.setState({name: '啦啦啦啦'}))
}
handleClick2(name){
console.log(111,this,this.setState({name: name}))
}
//方法3
handleClick3 = ()=>{
console.log(111,this,this.setState({name: '啦啦啦啦'}))
}
render(){
return (
<div>
<button onClick={this.handleClick1}>构造函数中使用bind</button>
<button onClick={this.handleClick2.bind(this,'lisi')}>调用时使用bind</button>
<button onClick={this.handleClick3}>声明时使用箭头函数</button>
<button onClick={()=> this.handleClick2('zhangsan')}>调用时使用箭头函数</button>
<p>{this.state.name}</p>
</div>
)
}
}
export default News;