javascript - ES6 中嵌套类的上下文很奇怪

标签 javascript reactjs firefox webpack

我有以下嵌套类结构:

import React, {Component} from 'react';
import {TextField} from '@material-ui/core';
import './ProfileEditor.css';

export default class ProfileEditor extends Component {
    SyncedTextField = class SyncedTextField extends Component {
        onChange = event => {
            console.log(this);
        };

        render() {
            return (
                <TextField
                    {...this.props}
                    onChange={this.onChange}/>
            );
        }
    };

    render() {
        return (
            <form className={"ProfileEditor"}>
                <this.SyncedTextField/>
            </form>
        );
    }
}

当代码被Webpack捆绑并在Firefox中运行时,它正确运行this.onChange,但输出的this引用了的上下文改为 ProfileEditor 类。

这太奇怪了,因为在 JSX 中,当我引用“this”时,它正确地指向 SyncedTextField,但在 onChange 方法中,它指向 ProfileEditor

我确实向 ProfileEditor 添加了一些属性来进行健全性检查,这些属性按照 ProfileEditor 中的声明显示,即使在 SyncedTextField 中提供了冲突的定义也是如此。

有人可以告诉我如何避免此问题以及可能导致此问题的原因吗?

最佳答案

不正确的行为可能特定于浏览器开发工具。但在这种情况下,这是由转译器的工作方式引起的。 Babel 6 类字段(属于第 3 阶段提案)转换实现存在错误。

The example使用 Babel 输出编译 ProfileEditorthisonChange

这是SyncedTextField Babel 输出的构造函数:

function SyncedTextField() {
  var _ref2;

  var _temp2, _this2, _ret2;

  _classCallCheck(this, SyncedTextField);

  for (
    var _len2 = arguments.length, args = Array(_len2), _key2 = 0;
    _key2 < _len2;
    _key2++
  ) {
    args[_key2] = arguments[_key2];
  }

  return (
    (_ret2 = ((_temp2 = ((_this2 = _possibleConstructorReturn(
      this,
      (_ref2 =
        SyncedTextField.__proto__ ||
        Object.getPrototypeOf(SyncedTextField)).call.apply(
        _ref2,
        [this].concat(args)
      )
    )),
    _this2)),
    (_this2.onChange = function(event) {
      console.log(_this); // SHOULD BE _this2
    }),
    _temp2)),
    _possibleConstructorReturn(_this2, _ret2)
  );
}

请注意,转译器创建 _this , _this2等临时变量提供词法this在箭头函数中,但 Babel 使用了错误的变量。

onChange = ...类字段是语法糖:

  constructor(...args) {
    super(...args);

    this.onChange = event => {
        console.log(this);
    };
  }

何时 the example is changed from class fields to constructor code ,它输出SyncedTextField .

The same example使用 TypeScript 编译(React 模板中默认由 Stackblitz 使用)按预期工作并输出 SyncedTextFieldthisonChange .

由于类很少以这种方式定义,Babel bug 通常不适用。

SyncedTextField = class SyncedTextField extends Component {...}是一个反模式。没有理由像这样嵌套类表达式。它效率低下,因为它是在每个 ProfileEditor 上进行评估的。实例化。它应该是类声明,可以用作 <SyncedTextField/> this way.

即使SyncedTextField应定义为 ProfileEditor 的属性出于可测试性或可扩展性的原因,最好将其设置为原型(prototype)属性:

class SyncedTextField extends Component {...}

class ProfileEditor extends Component {
  get SyncedTextField() { return SyncedTextField }
  ...
}

关于javascript - ES6 中嵌套类的上下文很奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51645549/

相关文章:

reactjs - createContext 不接受 defaultValue

firefox - 通过 CSS 在 DIV 中使用 WIDTH 和 HEIGHT 百分比的问题(firefox 不工作)

ajax - jQuery $.ajax(), $.post 在 Firefox 中发送 "OPTIONS"作为 REQUEST_METHOD

javascript - 如何播放/暂停按钮

javascript - ElectronJS 和 React DevTools : "Extension server error: Operation failed: http://localhost:3000/has no execution context", 来源:devtools://

javascript - 通过 Ajax 加载的 PHP 未执行

reactjs - 是否可以覆盖一个特定 intl.formatMessage 的区域设置?

firefox - 带有socks v5代理的java runtime 6 - 可能吗?

javascript - 广播所有命令不自动删除广播 - Discord.js-Commando

javascript - jQuery Deferrable、Deferred 和 jQuery Deferred 之间的混淆