JavaScript getter 方法有什么意义?

What's the point of a JavaScript getter method?

我正在尝试了解以下各项的优势(如果有的话):

const obj = {
    forename: 'Foo',
    surname: 'Bar',
    get name() {
        //yes I get that I can do other stuff here
        return this.forename+' '+this.surname;
    }
}
alert(obj.name); //Foo Bar

...超过...

const obj = {
    forename: 'Foo',
    surname: 'Bar',
    name() {
        return this.forename+' '+this.surname;
    }
}
alert(obj.name()); //Foo Bar

我已经阅读了 (1; 2; 3),但似乎看不到除了可读性和代码风格之外的任何好处。仅此而已吗?两种方法之间没有隐含的行为变化?

是否着眼于未来 class property/method 在 JavaScript 中的可见性?这是有道理的——私有财产的吸气剂。但是由于还没有,所以我看不出上面的意思。

谁能教教我?

由于您只为 name 定义了 getter,而没有定义 setter,如果您尝试更改它的值,例如 obj.name = "foo",则什么都不会发生发生。

另一方面,如果您尝试更改第二个对象上的 name 属性,没有什么能阻止您这样做。

一个区别是 typeof 在使用 getter 时实际上会 按预期 工作,也就是说,它将 return 实际类型原始 return 由 getter 编辑,而使用方法将始终 return function:

const objGetter = {
  forename: 'Foo',
  surname: 'Bar',
  get name() {
    return `${ this.forename } ${ this.surname }`;
  }
}

const objGetterLogic = {
  forename: undefined,
  surname: 'Bar',
  get name() {
    return this.forename ? this.surname : 3;
  }
}


const objMethod = {
  forename: 'Foo',
  surname: 'Bar',
  name() {
    return `${ this.forename } ${ this.surname }`;
  }
}

console.log(`objGetter`, typeof objGetter.name);
console.log(`objMethod`, typeof objMethod.name);
console.log(`objGetterLogic (without forename)`, typeof objGetterLogic.name);

objGetterLogic.forename = 'Alice';

console.log(`objGetterLogic (with forename)`, typeof objGetterLogic.name);

当然,你可以在有方法的版本中调用name(),但是用getter会透明工作。

此外,如果您嵌套了 getters,您可以透明地调用它们,如果您以编程方式导航对象,这会派上用场,否则,您需要考虑这种可能性属性的数量是一个值或一个 function 需要被调用以获得您需要的实际值:

class Shape {  
  constructor(type, children) {
    this.type = type || '';
    this.children = children || [];
  }
  
  get firstChild() {
    return this.children[0];
  }
  
  get lastChild() {
    return this.children[this.children.length - 1];
  }
}

const group1 = new Shape('group1', [
  new Shape('a'),
  new Shape('b'),
  new Shape('c'),
]);

const group2 = new Shape('group2', [
  new Shape('d'),
  new Shape('e'),
  new Shape('f'),
]);

const group4 = new Shape('group4', [
  group1,
  group2,
]);

console.log(group4.firstChild.lastChild.type);

无论如何,我认为 getters 和 setter 的最大优势之一就是增加可读性和减少冗长,尽管这通常归结为个人偏好。无论如何,我宁愿使用:

person.name = 'Alice Smith';

比:

person.setName('Alice', 'Smith');

但我们也可以说后者在某些情况下可能更合适。

由于这两个特性的能力是相同的,我们需要考虑与这样的属性(或方法)交互的代码的可读性和可写性。

整个优势是在访问 属性 时能够 运行 发挥作用。 "Ah," 你说,"but if I wanted to run a function, I'd just use a function." 你是对的——正如我最初所说的——两者在能力方面没有区别。但是访问 属性 不同于为编写与您的对象交互的代码的人调用函数。

从逻辑上讲,我希望访问器方法的名称以 get 开头。您的示例函数 name 对我来说似乎风格不佳,而 属性 称为 name 似乎好多了。如果你问我 obj.getName()obj.name 有什么优势,我可以很容易地告诉你后者输入起来要短得多! setters 存在相应的可读性问题:obj.setBirthday(new Date(...)) 与 setter 属性、obj.birthday = new Date(...)(假设,例如,这会改变相应的 age 属性)

就是这样——所有语言都旨在使人类作者和读者更容易理解图灵完备的功能集。如果某项功能不能帮助您实现该目标,请不要使用它!

  1. 作为一种语法糖,它可以使您的代码更具可读性,但至少可以减少阻塞:x = a().b().c().d() vs x = a.b.c.d
  2. 假设您已经有这样的代码obj.attr...很多这样的代码,并且在某些时候您意识到在所有这些地方都需要一个函数而不是访问运算符Get/set 救援。在调试中特别有用,可以捕获 属性 访问。更重要的是,如果您必须使用代码,您将无法控制
  3. 有时使用 getter 更符合习惯。 Reader 期望 obj.attr 没有副作用,但他不太确定他是否看到一个函数