JavaScript 挫败:类和类属性的转换

2025-06-07

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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

我震惊地发现,当我点击按钮时,浏览器抱怨该setState方法不存在!

事实证明,即使使用了ES2015 中首次出现的class语法,类的方法也并未绑定到给定的实例。不知何故,我之前竟然没有意识到这一点。这还是一个this依赖于调用上下文的老问题。如果我们想让代码正常工作,就必须自己绑定方法,例如:

class Login extends React.Component {
  constructor() {
    super()
    this.login = this.login.bind(this);
    //etc...
  }
}
Enter fullscreen mode Exit fullscreen mode

现在,我在网上看到的实际示例使用了一种我不熟悉的语法,大概是为了解决这个问题。原来,它叫做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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

我不太明白这个语法是怎么回事。我不是语言专家,也不是 JavaScript 专家,但它看起来就是不对劲。

如果我们class用替换function,它会让我想起这样的事情:

function Login() {
  this.state = {
    redirectToReferrer: false
  }

  this.login = () => {
    fakeAuth.authenticate(() => {
      this.setState(() => ({
        redirectToReferrer: true
      }))
    })
  } 
}
Enter fullscreen mode Exit fullscreen mode

如果我们使用创建一个实例new Login()this.setState那么无论调用上下文如何,它都可以工作。

但是,在这种情况下,使用类并添加这种新的转换语法真的值得吗?就好像这种新语法试图弥合使用functionclass语法所能实现的功能之间的差距:我们不能直接this.state = valueclass构造函数外部写入,但现在我们终于可以通过转换类属性来实现了。在这种情况下,也许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()
Enter fullscreen mode Exit fullscreen mode

当我们使用带有“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)
Enter fullscreen mode Exit fullscreen mode

看来arrowFunction原型链中没有解决这个问题。我不知道这是预期行为还是一个 bug。

这类事情让我对 JavaScript 感到沮丧。感觉 JavaScript 就像在追逐自己的尾巴,不断地添加语法糖,最终结果仍然令人困惑。我不知道这里面究竟有什么内在的考虑,但看起来,如果 JavaScript 要拥有一种class语法,那么以一种更正交的方式实现,这样就不需要一直添加新的语法了,这似乎很好。

我对这种语法感到失望是错误的吗?我一直对不同的观点持开放态度。

文章来源:https://dev.to/nestedsoftware/javascript-frustration-classes-and-class-properties-transform-16gl
PREV
神经网络入门
NEXT
如何(不)学习