对于新手学习React中事件处理这一章节,大多数会在使用bind(this)绑定this这个操作上深感疑惑。最近被问到这个问题,感觉没有通俗易懂的语言能够讲清楚这个知识点。于是去React官网上看了一下官网的解释和网上一些其他的说法之后,感觉能把初学者整跑路。
所以自己就来这里记录一下了,希望对于初学者来说有帮助。这里我们先来看一个简单的案例,案例里我们定义了一个有状态组件Hello,在这个组件里我们定义了一个updateInfo方法。要想使用this.updateInfo这个函数方法就必须在constructor中去使用bind(this)方法绑定this,否则this就是undefined。
class Hello extends React.Component {
constructor(props) {
super(props)
this.state = {
age: 13,
flag: true
}
this.updateInfo = this.updateInfo.bind(this)
}
// 如果使用函数的形式直接定义,要在constructor里面去绑定this改变this的指向
updateInfo() {
console.log(this)
this.setState({
age: 5
})
}
render() {
return <div>
<p>这是一个有状态组件</p>
<p>年龄:{this.state.age}</p>
<button onClick={this.updateInfo}>更新年龄</button>
</div>
}
}
问题就此产生了,为什么要绑定this才能用呢?其实这里我们最去了解一下在咱们ES5中的构造函数和ES6的类的概念,这个问题的答案就非常通俗易懂了。
首先我们来看一下以下代码案例,大家注意看里面的注释,这段代码的精髓都在注释里了:
// js中构造函数的写法
function Person(x, y) {
this.x = x
this.y = y
}
Person.prototype.add = function() {
console.log(this.x+this.y)
}
let p = new Person(1, 2)
// 上面的代码用ES6的class改写,就是下面这样
class Persons {
constructor(x, y) {
this.x = x
this.y = y
}
add() {
console.log(this.x+this.y)
}
}
// 这个时候我们来看一下Persons的类型以及Persons这个类跟构造函数的关系
typeof Persons // "function"
Persons === Persons.prototype.constructor // true
// 我们发现Persons类的数据类型就是函数,类本身就指向构造函数
// 由此可见,构造函数的prototype属性,在ES6的class里同样存在着
所以通过上面的代码我们能够得出的结论是:类的所有方法都定义在类的prorotype上面,
class Persons {
constructor() {}
add() {}
}
// 等同于
Persons.prototype = {
constructor() {},
add() {}
}
在这个实例代码中我们能看到,constructor()、add()其实都是定义在Persons.prototype上。所以,在类的实例上调用方法,其实就是调用原型上的方法。这里我们还可以用一个案例来验证一下:
class Hello{}
let h = new Hello()
h.constructor === Hello.prototype.constructor // true
// h是Hello的实例,它的constructor()方法就是Hello类原型的constructor()方法
所以在ES6的类中,跟ES5是一样的是,实例的属性只有定义在自身的时候(也就是通过this.属性这种形式)是定义在this对象上,其他都是定义在原型上(即定义在class上)。
下面我们再来看一个案例代码:
class Hello {
constructor(x, y) {
this.x = x
}
add() {
console.log(this.x);
}
}
var hello = new Hello(2);
hello.add() // 2
// 我们用hasOwnProperty看看对象自身属性中是否具有指定的属性
hello.hasOwnProperty('x') // true
hello.hasOwnProperty('add') // false
hello.__proto__.hasOwnProperty('add') // true
add方法被定义在了原型上面,所以这个时候如果想要add方法变成对象自身的方法,就需要去改变this指向,也就回到了我们文章开始的案例那样,使用bind(this)方法进行绑定:
class Hello {
constructor(x, y) {
this.x = x
this.add = this.add.bind(this)
}
add() {
console.log(this.x);
}
}
var hello = new Hello(2);
hello.add() // 2
hello.hasOwnProperty('x') // true
hello.hasOwnProperty('add') // true
hello.__proto__.hasOwnProperty('add') // true
到这里大家应该明白了为什么要绑定this了吧,当然了,在React当中绑定this的方法有好几种,大家弄清楚了这一种之后,其他的也就懂了。