8

我正在阅读有关 JavaScript 类的内容,并遇到了“公共类字段语法”这个术语。在深入研究它时,我遇到了这个Babel 的关于类属性的文档

有人可以解释一下 -实现方面这种新语法的用例是什么? (它为 JavaScript 提供了哪些解决方案/好处,到目前为止还没有这些解决方案/好处?)

下面是一个示例(在 Google Chrome 中运行没有错误)

class Person {
    firstName = "Mike";
    lastName = "Patel";
    
    // this is a public class field syntax
    getName = () => {
      return this.firstName + " " + this.lastName;
    };
}

var p = new Person();

console.log(p.firstName); // Mike
console.log(p.lastName); // Patel
console.log(p.getName); // () => { return this.firstName + " " + this.lastName; }
console.log(typeof p.getName); // function
console.log(p.getName()); // Mike Patel

4

3 回答 3

17

简单地说,使用它的原因是易于理解代码。如果没有类字段声明,您将执行以下操作:

class Person {
  constructor() {
    this.firstName = "Mike";
    this.lastName = "Patel";

    this.getName = () => {
      return this.firstName + " " + this.lastName;
    };
  }
}

var p = new Person();

console.log(p.firstName); // Mike
console.log(p.lastName); // Patel
console.log(p.getName); // () => { return this.firstName + " " + this.lastName; }
console.log(typeof p.getName); // function
console.log(p.getName()); // Mike Patel

可行,但现在您将可调用getName()的和其余的普通实例属性都收集在构造函数中。您可以拥有更多,这意味着您的类定义总体上看起来毫无意义:

class MyClass() {
  constructor(someArg) {
    this.foo1 = 1;
    this.foo2 = 2;
    this.foo3 = 3;
    this.foo4 = someArg;

    this.bar1 = () => {}
    this.bar2 = () => {}
    this.bar3 = () => {}
    this.bar4 = () => {}
  }
}

等等。同样,一切都在构造函数中。如果您有很多代码,则很难阅读什么是什么。如果构造函数接受任何参数,那么您将有额外的开销来跟踪这些参数。因此,它难以阅读,难以维护,这一切都没有真正的好处。你把所有东西都塞在同一个地方。

使用类字段声明,将它们分开并得到

class MyClass() {
  /* properties - do not depend on the constructor*/
  foo1 = 1;
  foo2 = 2;
  foo3 = 3;
  foo4; /* this is a property that this class will have - 
          I do not need to look at the constructor to know about it */

  /* easy to see what the constructor does that is only about *constructing* the object */
  constructor(someArg) {
    this.foo4= someArg;
  }

  /* callable field are separated from the rest of the simple properties and construction logic */
  bar1 = () => {}
  bar2 = () => {}
  bar3 = () => {}
  bar4 = () => {}
}

所以,总而言之,它不是革命性的,但它的语法稍微好一点,可以更容易地表达一个类的内容。

于 2019-08-22T12:11:02.293 回答
3

引用类字段提案

通过预先声明字段,类定义变得更加自文档化;实例经历较少的状态转换,因为声明的字段始终存在。

类字段的引入还允许私有类字段,这也带来了一些好处:

通过定义在类之外不可见的东西,ESnext 提供了更强的封装,确保您的类的用户不会因依赖内部而意外绊倒自己,这可能会更改版本。

于 2019-08-22T12:06:49.243 回答
-1

它源于这个正在解决“问题”的提案。

预提案

假设你想要一个Foo拥有默认属性的类,那么你可以直接写如下

class Foo {
  defaultAttribute = 'default';
  getDefault() { return this.defaultAttribute; }
}

请记住,上面的提案并未在 atm 中实施。defaultAttribute = '...'设置类对象时(编译时)将被忽略。它甚至不是原型或字段成员(函数对象)的一部分。那是因为defaultAttribute编译器没有拾取。因此你不能这样做foo.defaultAttribute

调用getDefault()会在这里抛出一个错误,因为此时它是未定义的。如果您在构造函数中提供值,该函数确实有效defaultAttribute

class Foo {
  defaultAttribute = 'default';
  constructor() {
    this.defaultAttribute = 'hello';
  }
  getDefault() { return this.defaultAttribute; }
}

在这种情况下,defaultAttribute设置为 'Hello' 但它没有覆盖原始变量'default'

提案后

通过该提案,“忽略”问题得到解决,您可以按照您刚刚描述的方式进行操作:

class Foo {
  defaultAttribute = 'default';
  getDefault() { return this.defaultAttribute; }
}

有了这个,你可以跳过使用constructor()

class Foo1 {
  defaultAttribute = 'default';
  getDefault() { return this.defaultAttribute; }
}

class Foo2 {
  defaultAttribute = 'default';
  constructor() {this.defaultAttribute = 'hello';}
  getDefault() { return this.defaultAttribute; }
}

const foo1 = new Foo1();
const foo2 = new Foo2();

console.log(foo1.getDefault());
console.log(foo2.getDefault());

于 2019-08-22T12:17:07.003 回答