什么是JavaScript中的“类字段”?

时间:2019-08-22 11:40:10

标签: javascript ecmascript-6 ecmascript-next

我正在阅读有关JavaScript类的内容,偶然发现了“ 公共类字段语法”这个术语。在深入研究它时,我遇到了这个Babel's documentation on class properties

有人可以解释一下吗-实施方面,这种新语法的用例是什么? (到目前为止,它为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

3 个答案:

答案 0 :(得分:2)

简而言之,使用此代码的原因是易于理解代码。没有类字段声明,您将执行

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

可行,但是现在您同时具有方法声明 instance属性都收集在构造函数中。但是,您可以有更多的方法,这意味着您的类定义总体上看起来毫无意义:

class MyClass() {
  constructor(someArg) {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 3;
    this.prop4 = someArg;

    this.method1 = () => {}
    this.method2 = () => {}
    this.method3 = () => {}
    this.method4 = () => {}
  }
}

,依此类推。同样,一切都在构造函数中。如果您有很多代码,那么很难读懂什么是什么。而且,如果构造函数接受任何参数,那么您就有额外的开销来跟踪这些参数。简而言之,它很难阅读,很难维护,没有真正的好处。您将所有东西都塞在同一位置。

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

class MyClass() {
  /* properties - don't depend on the constructor*/
  prop1 = 1;
  prop2 = 2;
  prop3 = 3;
  prop4; /* this is a property that this class will have - 
          I don't 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.prop4 = someArg;
  }

  /* methods are separated from the rest of the properties and construction logic */
  method1 = () => {}
  method2 = () => {}
  method3 = () => {}
  method4 = () => {}
}

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

答案 1 :(得分:1)

引用class fields proposal

  

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

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

  

通过定义在类外部不可见的内容,ESnext提供了更强的封装,确保您的类用户不会因内部而意外绊倒,因为内部可能会改变版本。

答案 2 :(得分:0)

它源自this proposal,其中正在解决“问题”。

预提案

假设您要拥有一个包含默认属性的类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());