javascript - ES6 中嵌套类的上下文很奇怪
问题描述
我有以下嵌套类结构:
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 阶段提案)转换实现中有一个错误。
使用 Babel 编译的示例ProfileEditor
输出如this
.onChange
这是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);
};
}
当示例从类字段更改为构造函数代码时,它会输出SyncedTextField
.
使用 TypeScript 编译的相同示例(在 React 模板中默认由 Stackblitz 使用)按预期工作,并且输出SyncedTextField
为this
.onChange
由于很少以这种方式定义类,因此 Babel 错误通常不适用。
SyncedTextField = class SyncedTextField extends Component {...}
是一种反模式。没有理由像这样嵌套类表达式。它是低效的,因为它是在每个ProfileEditor
实例化时评估的。应该是类声明,可以作为<SyncedTextField/> this way.
即使出于可测试性或可扩展性的原因SyncedTextField
应将其定义为ProfileEditor
组件的属性,最好将其设为原型属性:
class SyncedTextField extends Component {...}
class ProfileEditor extends Component {
get SyncedTextField() { return SyncedTextField }
...
}
推荐阅读
- eclipse - 无法在 Eclipse 中读取位于 https://ecd-plugin.github.io/update/content.xml 的存储库
- r - 绘制不同几何图形时的图例类型
- c++ - 将 Facebook Proxygen 与 Cmake 链接
- javascript - 如何在 Jupyter 笔记本中将 HTML 元素与 Python 函数链接?
- python - 不同的mysql select语句但睡眠时间很长
- java - Spring EL 无法在 xml 配置文件的 Integer 属性中解析
- solr - Solr:如何对具有多个字段的文档进行 DISTINCT(field1, field2, field3) 搜索?
- dolphindb - 使用 DolphinDB MySQL 插件失败
- php - htacess 重写规则在查询字符串中返回错误值
- java - 解析文本文件并删除java中双引号内的逗号