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


102

对于ECMAScript 6类中的getter和setter的意义,我感到困惑。什么目的?以下是我要参考的示例:

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 TorresSánchez15年


可以在以下位置找到很好的文章,对此进行解释:coryrylan.com/blog/javascript-es6-class-syntax “在上面的类中,我们的name属性具有getter和setter。我们使用'_'约定创建后备字段来存储我们的name属性。每次调用get或set时,如果不执行此操作,则将导致堆栈溢出”。它还谈到变量并非真正是“ private”,但是有许多新方法可以在其中创建私有var JS类;我最喜欢的只是使用Typescript,但我也使用了Symbol方法
webdevinci

Answers:


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
您是说属性而不是属性?我有点困惑
Krizzu

好眼睛,@ Krizzu。属性存在于JavaScript中,与属性完全不同。答案的确是针对属性而不是属性。我已经编辑了答案。我认为回答者不会介意的。:)
Ray Toal

我不太确定这真的是一个优点,它某种程度上掩盖了使用setters / getters的概念。类的客户可能会认为它直接使用属性,而不合适的是属性,但我同意它遵循信息/细节隐藏原则。也许如果因此使用它,它会使使用变得更容易,而我只需要习惯更多...
ChristofKälin,2015年

如果可以,可以在设置器中传递多个参数吗?@David Laberge
Vignesh S

如果您想手动创建setter和getter,那么这是来自coryrylan.com/blog/javascript-es6-class-syntax的一个很好的示例。设置:set name(newName) { this._name = newName; }获取:get name() { return this._name.toUpperCase(); }
Jim Doyle,

48

ES6中的Getter和Setter具有与其他语言(包括ES5)相同的目的。ES5已经允许通过的getter和setter方法Object.defineProperty,尽管它们不太干净且使用起来比较麻烦。

实际上,getter和setter允许您对读取和写入使用标准的属性访问表示法,同时仍然能够自定义如何检索和更改属性,而无需显式的getter和setter方法。

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

console.log(someEmployee.name);

看起来像是普通的属性访问,但实际上会toUpperCase在返回名称之前调用该名称。同样,这样做:

someEmployee.name = null;

会访问setter,并且不会_name由于namesetter中引入的guard子句而修改内部属性。

另请参见一般性问题:为什么使用吸气剂和吸气剂?有关为何能够修改成员访问功能的有用信息。


3

与Java中的类似概念相比,ES6获取器和设置器的动机大不相同。

在Java中,getter和setter允许类定义JavaBean。获取器和设置器的要点是,它允许bean具有与公共字段所隐含的接口完全正交的“接口”。因此,我可以有一个不是JavaBean属性的字段“名称”,而我可以有一个不是字段的JavaBean属性“地址”。

JavaBean属性还可以通过Java反射被数千个框架(例如,Hibernate)“发现”。因此,getter和setter是“暴露” bean属性的标准方法的一部分。

作为函数的获取器和设置器也具有它们“抽象”实现的价值。它既可以是字段,也可以是计算值(“合成”)。因此,如果我有一个名为“ zipcode”的bean属性,则该属性以存储的字符串开头。现在假设我想将其更改为根据地址/城市/州计算得出的值?

如果使用字段,此代码将中断:

      String zipcode = address.zipcode();

但是,如果我使用吸气剂,则不会中断:

      String zipcode = address.getZipcode();

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

但这比Java更好一点,尽管Java不允许您将“字段”兼容地转换为方法,但ES6 GET和SET允许这样做。

也就是说,如果我有:

       var zipcode = address.zipcode;

如果我将邮政编码从标准对象属性更改为吸气剂,那么上面的代码现在将调用GET函数。

请注意,如果我未在定义中包含GET,则不会调用邮政编码GET方法。相反,它只会将功能邮政编码分配给var。

因此,我认为这些是理解Java和JavaScript ES6获取器和设置器之间的一些重要区别。


0
class Employee {

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

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

    get name() {
      // when you get this by employeeInstance.mame
      // 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 blew 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 success, because the `if check`
  console.log(employeeInstance.name)

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

但无论如何,getter并且setter就像是一个间谍。它监视对象的属性,以便您每次获取或设置该属性的值时都可以执行某些操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.