ECMAScript 6类中的getter和setter是用来做什么的?

112

我对 ECMAScript 6 类中 getters 和 setters 的作用感到困惑。这是什么目的?以下是我参考的一个示例:

class Employee {

    constructor(name) {
        this._name = name;
    }

    doWork() {
        return `${this._name} is working`;
    }

    get name() {
        return this._name.toUpperCase();
    }

    set name(newName){
        if(newName){ 
            this._name = newName;
        }
    }
}

1
如果你了解C#,那么这个与之类似。 - Arturo Torres Sánchez
我们上面的类有一个获取器和设置器来获取和设置我们的名称属性。我们使用“_”约定来创建一个后备字段来存储我们的名称属性。如果没有这个,每次调用get或set都会导致堆栈溢出。它还提到变量并不真正是“私有的”,但是有许多新的方法可以在JS类中创建私有变量;我的最爱就是使用TypeScript,但我也使用过Symbol方法。 - webdevinci
4个回答

108

这些 setter 和 getter 允许您直接使用属性(而无需使用括号)

var emp = new Employee("TruMan1");

if (emp.name) { 
  // uses the get method in the background
}

emp.name = "New name"; // uses the setter in the background

这仅用于设置和获取属性值。


1
你是不是想说“属性”而不是“特性”?这有点让我困惑。 - Krzysztof Borowy
很好,@Krizzu。在JavaScript中存在属性,它们与属性完全不同。答案确实是指属性而不是属性。我已经编辑了答案。我认为回答者不会介意。 :) - Ray Toal
我不太确定这是否真的是一个优势,它有些隐藏了使用setter/getter的概念。一个类的客户端可能会认为它直接使用属性,而这并不合适,但我同意它遵循了信息/细节隐藏原则。也许如果我们坚持使用它,它会使使用更容易,我只需要更习惯它... - Christof Kälin
你能在setter中传递多个参数吗?如果可以,那么如何使用它?@David Laberge - Vignesh S
如果您想手动创建setter和getter,这里有一个很好的例子来自https://coryrylan.com/blog/javascript-es6-class-syntax Set: set name(newName) { this._name = newName; } Get: get name() { return this._name.toUpperCase(); } - Jim Doyle

51

ES6中的Getter和Setter与其他语言(包括ES5)具有相同的作用。ES5已经通过Object.defineProperty允许使用Getter和Setter,但是它们不够简洁,使用起来更加繁琐。

实际上,Getter和Setter允许您使用标准属性访问符号进行读取和写入,同时仍然具有自定义如何检索和修改属性的能力,而无需显式使用Getter和Setter方法。

在上面的Employee类中,这意味着您可以像这样访问name属性:

console.log(someEmployee.name);

它看起来像是一个普通的属性访问,但实际上在返回它之前会调用toUpperCase函数将名称转换为大写。同样地,执行以下操作:

someEmployee.name = null;

访问setter,由于在name的setter中引入了守卫语句,因此不会修改内部_name属性。

有关为什么能够修改成员访问功能很有用的更多信息,请参见通用问题 为什么使用getter和setter?


11
class Employee {

    constructor(name) {
      this._name = name;
    }

    doWork() {
      return `${this._name} is working`;
    }

    get name() {
      // when you get this by employeeInstance.name
      // the code below will be triggered
      // and you can do some logic here
      // just like `console.log` something you want
      console.log('get triggered!')
      return this._name.toUpperCase();
    }

    set name(newName) {
      // the same as `get`
      // when you employeeInstance.mame = 'xxx'
      // the code below will be trigged
      // and you can also do some logic 
      // like here is a `console.log` and `if check`
      console.log('set triggered!')
      if (newName) {
        this._name = newName;
      }
    }
  }

  const employeeInstance = new Employee('mike')
  employeeInstance.name
  employeeInstance.name = '' // this won't be successful, because the `if check`
  console.log(employeeInstance.name)

  // => 
  // get triggered
  // set triggered
  // get triggered
  // MIKE

无论如何,gettersetter就像间谍一样。它们监视对象的属性,这样你就可以在获取或设置属性值时执行某些操作。

4

ES6的getter和setter与Java中类似概念有截然不同的动机。

在Java中,getter和setter允许一个类定义一个JavaBean。getter和setter的重点在于,它允许bean拥有一个完全正交的“接口”,而不是公共字段所暗示的接口。因此,我可以有一个名为“name”的字段,它不是JavaBean属性,我也可以有一个名为“address”的JavaBean属性,它不是一个字段。

JavaBean属性也可以通过Java反射由数千个框架(例如Hibernate)进行“发现”。因此,getter和setter是“公开”bean属性的标准方法之一。

作为函数,getter和setter还具有抽象实现的价值。它可以是字段或计算出的(“合成”)值。所以,如果我有一个名为“zipcode”的bean属性,它最初存储为字符串。现在假设我想将其更改为从地址/城市/州计算出的值?

如果使用字段,则此代码将会出错:

      String zipcode = address.zipcode();

但是,如果我使用getter,这不会出现问题:

      String zipcode = address.getZipcode();

JavaScript没有像JavaBeans一样的东西。据我所知,GET和SET的预期值仅限于上述“合成”(计算)属性。

但是它比Java要好一些,因为虽然Java不允许您将“字段”兼容地转换为方法,但ES6 GET和SET允许这样做。

也就是说,如果我有:

       var zipcode = address.zipcode;

如果我将邮政编码从标准对象属性更改为getter,上述代码现在调用GET函数。
请注意,如果我没有在定义中包括GET,则不会调用zipcode GET方法。相反,它只会将函数zipcode分配给变量。
因此,我认为这些是理解Java和JavaScript ES6 getter和setter之间的一些重要区别。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接