类 和 React 组件中的 this 关键字行为(箭头函数与常规函数)

this keyword behavior in classes and react component ( Arrow function vs regular function)

我正在尝试了解 this 关键字在与事件处理程序配对时在反应组件中的行为(箭头函数与常规函数)。

为此,我创建了两个示例,一个使用 HTML/vanilla JS,另一个使用 React。

HTML/VanillaJS

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="btn-arr">Log this Arr</button>
    <button class="btn-reg">Log this Reg</button>

    <script>

        class App {
            logThisArr = () => {
                console.log('Arr : ', this);
            };
            logThisReg = function () {
                console.log('Reg : ', this);
            };
        }

        const app = new App();

        const btnArr = document.querySelector('.btn-arr');
        const btnReg = document.querySelector('.btn-reg');

        btnArr.addEventListener('click', app.logThisArr); // Arr : App {logThisArr: ƒ, logThisReg: ƒ}

        btnReg.addEventListener('click', app.logThisReg); // Reg : <button class="btn-reg">Log this Reg</button>

    </script>
</body>

</html>

反应

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';

class App extends Component {
    logThisArr = () => {
        console.log('arrow : ', this);
    };
    logThisReg = function() {
        console.log('Reg : ', this);
    };

    render() {
        return (
            <div className="App">
                <button onClick={this.logThisArr}>Log this Arr</button>
                {/* Arr : App {props: {…}, context: {…}, refs: {…}, updater: {…}, logThisArr: ƒ, …}*/}

                <button onClick={this.logThisReg}>Log this Reg</button>
                {/*Reg : undefined */}
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

为什么我在使用常规函数时得不到相同的输出? 在反应中,我得到 "undefined",在 vanillaJS 中,我得到按钮对象。

谢谢!

您不必处理 this。但不要忘记绑定回调事件 ( React Doc about events ) 以始终拥有良好的 ref

只需将此添加到 App 组件

  constructor(props) {
    super(props);
    this.logThisArr = this.logThisArr.bind(this);
    this.logThisReg = this.logThisReg.bind(this);
  }

好的,那么,谢谢你们。

经过大量阅读,我觉得我理解得更好一些。

它比原来的 post 更深入。 我们首先需要了解"execution context"和"lexical scope"的区别。 http://ryanmorr.com/understanding-scope-and-context-in-javascript/

然后我们可以开始查看 "this" 在常规函数和箭头函数中的行为。

正则函数内部:

  • "this" 值根据 "execution context" 而变化,换句话说,"this" 是对调用它的人或对象的引用(通常是一个对象,即按钮对象或 class 实例化对象)。
  • 如果 "nothing" 调用它(尤其是回调的情况),那么 "this" 将失去对调用它的初始对象的引用并设置为默认值(该默认值取决于我们是在节点中,还是在浏览器中,还是在严格模式下,还是在使用库(不确定库,但我认为?))
  • 可以使用 "call()"、"apply()" 和 "bind()".
  • 显式指定 "this" 值

内部箭头函数:

  • 箭头函数没有自己的 "execution context"
  • 箭头函数在声明中静态绑定上下文,换句话说,"this" 的值是永久的 "captured" 并且它几乎总是引用 "this" 的值函数的 "parent/enclosing lexical scope"(=父上下文)。
  • "this" 值永远无法重新绑定。但是箭头函数中的其他参数可以用 "bind()" 关键字重新绑定。
  • 在对象文字中使用箭头函数定义方法的特殊情况下,"this" 指的是 window 对象:https://dmitripavlutin.com/when-not-to-use-arrow-functions-in-javascript/

这就是为什么在 react 中使用箭头函数或使用“.bind()”是必要的,因为我们不能依赖常规函数(其中 "this" 不断变化)来访问属性我们实例化的 App class.

对象

在我们的具体情况下,至于为什么我在反应代码中使用常规功能时得到 "undefined",TBT 我不太确定(可能是因为反应内部恶作剧)但我可以猜到这是因为两件事:

  • "this" 丢失了它的 "execution context"(换句话说,它丢失了对调用它的对象的引用)所以它成为默认值(或者 "undefined",当在 "strict mode", 或 "window object" 当不在严格模式和浏览器中时)
  • 在 ES6 classes 中,默认的隐式设置设置为 "strict mode",因此我们得到 "undefined".

无论如何,这并不详尽,我还没有完全理解,但我现在更好地理解了为什么我们需要 bind/use React 中的箭头功能以及它们的工作原理。

这些真的帮助我弄清了事情的真相:

还有@brian Thomoson 提到的link: How to access the correct `this` inside a callback?

谢谢大家

此致,