JavaScript 挫败:类和类属性的转换
最近我一直在学习 React,在 JavaScript 中遇到了一些我没有预料到的事情。
以下是我正在尝试的一些代码示例。此代码是https://reacttraining.com/react-router/web/example/auth-workflow代码的修改版本。
class Login extends React.Component {
constructor() {
this.state = {
redirectToReferrer: false
}
}
login() {
fakeAuth.authenticate(() => {
//the problem is here
this.setState(() => ({
redirectToReferrer: true
}))
})
}
render() {
//...some additional logic here
return (
<div>
<p>You must log in to view the page</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
我震惊地发现,当我点击按钮时,浏览器抱怨该setState
方法不存在!
事实证明,即使使用了ES2015 中首次出现的class
语法,类的方法也并未绑定到给定的实例。不知何故,我之前竟然没有意识到这一点。这还是一个this
依赖于调用上下文的老问题。如果我们想让代码正常工作,就必须自己绑定方法,例如:
class Login extends React.Component {
constructor() {
super()
this.login = this.login.bind(this);
//etc...
}
}
现在,我在网上看到的实际示例使用了一种我不熟悉的语法,大概是为了解决这个问题。原来,它叫做Class properties transform 。目前, Babel已使用stage-2预设版本支持该语法。新语法如下:
class Login extends React.Component {
//class properties transform
state = {
redirectToReferrer: false
}
//class properties transform
login = () => {
fakeAuth.authenticate(() => {
this.setState(() => ({
redirectToReferrer: true
}))
})
}
render() {
//...some additional logic here
return (
<div>
<p>You must log in to view the page</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
我不太明白这个语法是怎么回事。我不是语言专家,也不是 JavaScript 专家,但它看起来就是不对劲。
如果我们class
用替换function
,它会让我想起这样的事情:
function Login() {
this.state = {
redirectToReferrer: false
}
this.login = () => {
fakeAuth.authenticate(() => {
this.setState(() => ({
redirectToReferrer: true
}))
})
}
}
如果我们使用创建一个实例new Login()
,this.setState
那么无论调用上下文如何,它都可以工作。
但是,在这种情况下,使用类并添加这种新的转换语法真的值得吗?就好像这种新语法试图弥合使用function
和class
语法所能实现的功能之间的差距:我们不能直接this.state = value
在class
构造函数外部写入,但现在我们终于可以通过转换类属性来实现了。在这种情况下,也许class
一开始就应该允许它。
super
我还尝试了一下这个新语法如何处理继承。如果超类中有一个普通方法,而子类中有一个同名的箭头函数,那么在子类方法中调用它实际上是可行的。
但是,super
如果超类和子类都使用箭头语法,则目前不起作用:
class BaseClass {
arrowFunction = () => {
console.log('BaseClass arrowFunction called')
}
}
class SubClass extends BaseClass {
arrowFunction = () => {
super.arrowFunction()
console.log('SubClass arrowFunction called')
}
}
const t = new SubClass()
t.arrowFunction()
当我们使用带有“env”和“stage-2”预设的 Babel 转换此代码并尝试在节点中运行生成的代码时,我们得到:
C:\dev\test.js:34
_get(SubClass.prototype.__proto__
|| Object.getPrototypeOf(SubClass.prototype), 'arrowFunction', _this).call(_this);
^
TypeError: Cannot read property 'call' of undefined
at SubClass._this.arrowFunction (C:\dev\test.js:34:96)
看来arrowFunction
原型链中没有解决这个问题。我不知道这是预期行为还是一个 bug。
这类事情让我对 JavaScript 感到沮丧。感觉 JavaScript 就像在追逐自己的尾巴,不断地添加语法糖,最终结果仍然令人困惑。我不知道这里面究竟有什么内在的考虑,但看起来,如果 JavaScript 要拥有一种class
语法,那么以一种更正交的方式实现,这样就不需要一直添加新的语法了,这似乎很好。
我对这种语法感到失望是错误的吗?我一直对不同的观点持开放态度。
文章来源:https://dev.to/nestedsoftware/javascript-frustration-classes-and-class-properties-transform-16gl