# 1. this关键字
直观上来说,我们可以将其按照`Java`语言中的写法来构建一个最初始的代码逻辑,比如:
~~~
class MyElement extends React.Component {
constructor() {
super();
this.datas= ["张三", "李四", "王五"]
}
// 点击处理
userClick() {
console.log(this)
}
render() {
return (
<ul>
{
this.datas.map((item, index) => {
return <li key={index} onClick={this.userClick}>{item}</li>
})
}
</ul>
)
}
}
~~~
运行后发现:打印的`this`为:
> undefined
那么,这种现象该如何解释呢?不妨在构造函数最后添加一个打印:
~~~
constructor() {
super();
this.datas= ["张三", "李四", "王五"]
console.log(this)
}
~~~
可以看看结果:
![](https://img.kancloud.cn/b3/fb/b3fbd09226dcf32176ffd505e60d3ebd_993x440.png)
也就是说这里在类中定义的方法`userClick`,定义在原型链上。也就是可以在`render`方法中可以使用`this`来调用到`userClick`方法,那么为什么在`userClick`方法中`this`为`undefined`呢?不妨来写一个原生的`JavaScript`来解释,比如下面的代码:
~~~
<script type="text/javascript">
"use strict"
class Demo{
showInfo(){
console.log(this)
}
}
console.log(new Demo().showInfo()); // undefined
</script>
~~~
结果:
> Demo {}
这里并没有因为开启了严格模式,从而导致定义的`userClick`方法内获取到的`this`为`undefined`。
不妨来看看文档的解释:[严格模式 - JavaScript | MDN (mozilla.org)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode)
* 在严格模式下通过`this`传递给一个函数的值不会被强制转换为一个对象。对一个普通的函数来说,`this`总会是一个对象。但,这种自动转化为对象的过程不仅是一种性能上的损耗,同时在浏览器中暴露出全局对象也会成为安全隐患,因为全局对象提供了访问那些所谓安全的`JavaScript`环境必须限制的功能的途径。
* 因此,对于一个开启严格模式的函数,指定的`this`不再被封装为对象,而且如果没有指定`this`的话它值是`undefined`。
也就是在上述代码的`userClick`函数中没有指定`this`?:
```
class MyElement extends React.Component {
...
// 点击处理
userClick() {
console.log(this)
}
...
}
```
那么,为什么在`userClick`函数中没有指定`this`,直观上来说在整个对象的封装中, `userClick`所指向的为当前类的实例对象,但在开启严格模式后,这里没有指定?
那么只可能为一种情况:
* `userClick`函数可能没有被当前类的实例调用。
这里按照`li`标签上的调用写一个类似的案例:
~~~
<script type="text/javascript">
class Demo{
showInfo(){
console.log(this)
return null
}
}
var demo = new Demo()
var method = demo.showInfo
method()
</script>
~~~
结果:
> undefined
因为在`onClick`函数中,也没有直接调用,而是使用类似赋值的方式。故而这里也就解释了为什么为`undefined`:
* 因为不是类的实例对象直接调用的,就回丢失`this`;
* 实际上和严格模式无关;
## 1.3 问题解决
解决方式有如下几种:
### 1.3.1 方式一:
使用箭头函数:
~~~
userClick = () => {
console.log(this)
}
render() {
return (
<ul>
{
this.datas.map((item, index) => {
return <li key={index} onClick={this.userClick}>{item}</li>
})
}
</ul>
)
}
~~~
值得注意的是,这种方式会将`userClick`方法放置在当前类定义之中:
![](https://img.kancloud.cn/a4/1b/a41b9f3ab8ec317a1c8511cde1ea3c46_991x463.png)
### 1.3.2 方式二:
~~~
userClick() {
console.log(this)
}
render() {
return (
<ul>
{
this.datas.map((item, index) => {
return <li key={index} onClick={() => {this.userClick()}}>{item}</li>
})
}
</ul>
)
}
~~~
这种方式`userClick`方法还是仅在原型链上:
![](https://img.kancloud.cn/be/cd/becd4f237861afbc85d886df69adae73_993x444.png)
### 1.3.3 方式三
使用绑定
~~~
constructor() {
super();
this.datas= ["张三", "李四", "王五"]
this.userClick = this.userClick.bind(this)
}
userClick() {
console.log(this)
}
render() {
return (
<ul>
{
this.datas.map((item, index) => {
return <li key={index} onClick={this.userClick}>{item}</li>
})
}
</ul>
)
}
}
~~~
值得注意的是,这种方式会将`userClick`方法放置在当前类定义之中:
![](https://img.kancloud.cn/a4/1b/a41b9f3ab8ec317a1c8511cde1ea3c46_991x463.png)