# 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)
}
~~~
可以看看結果:

也就是說這里在類中定義的方法`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`方法放置在當前類定義之中:

### 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`方法還是僅在原型鏈上:

### 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`方法放置在當前類定義之中:
