ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 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)