【问题标题】:What's the point of a JavaScript getter method?JavaScript getter 方法的意义何在?
【发布时间】:2020-01-02 19:50:16
【问题描述】:

我试图了解以下优势(如果有的话):

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),但除了可读性和代码风格之外,似乎没有任何好处。这就是全部吗?两种方法之间没有隐含的行为变化?

是否只关注 JavaScript 中未来的类属性/方法可见性?这是有道理的——私有财产的吸气剂。但既然还没到这里,我看不出上面的意思。

谁能赐教?

【问题讨论】:

  • 您可以拥有虚拟属性,而不仅仅是方法调用。曾经使用过 Knockout.JS 吗?它具有可通过函数调用访问的可观察类型(它允许您订阅更改,甚至订阅原语)。例如,如果你有一些长链,你最终会得到myViewModel.config().table().header.firstName。您必须记住这些属性中的 哪些 是可观察的,而不是调用那些是的。如果您将 header 更改为可观察对象,则需要更新对它的 all 调用。
  • 某些平台实际上已经支持私有字段,例如节点 13,我同意结合这些,getter 更有意义
  • 可能是 stackoverflow.com/questions/42342623/… 的副本(甚至有相同的代码示例)。
  • 谢谢大家 - 这里有一些伟大的贡献。正如我所怀疑的,它基本上只是语法和可读性。我只是想确保我没有遗漏两者之间隐含的行为差异。

标签: javascript oop getter-setter ecmascript-5


【解决方案1】:

一个区别是typeof 在使用 getter 时实际上会按预期工作,也就是说,它将返回 getter 返回的原始类型的实际类型,而使用方法将始终返回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。

此外,如果您有嵌套的 getter,则可以透明地调用它们,如果您以编程方式导航对象,这会派上用场,否则,您需要考虑属性可能是值或需要调用 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);

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

person.name = 'Alice Smith';

比:

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

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

【讨论】:

  • 哦,typeof 点很有趣 - 没有意识到这一点。嵌套的吸气剂很有趣,如果有什么东西可以通读并完全遵循的话。接受这个答案,因为我认为它涵盖了大多数基础。
【解决方案2】:

由于您只为name 定义了一个getter,而没有定义一个setter,如果您尝试更改其值,例如obj.name = "foo",则不会发生任何事情。

另一方面,如果您尝试更改第二个对象的 name 属性,这样做不会阻止您。

【讨论】:

  • 啊,好点 - 仔细想想,似乎很明显;对于第二个对象,写入obj.name 将覆盖该方法。
【解决方案3】:

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

整个优点是能够在访问属性时运行函数。 “啊,”你说,“但如果我想运行一个函数,我就使用一个函数。”你是对的——正如我最初所说的——两者在能力方面没有区别。但访问属性不同于为编写与您的对象交互的代码的人调用函数。

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

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

【讨论】:

  • 谢谢。这和我的想法差不多——在行为上没有实际差异,只是在风格和可读性上。
【解决方案4】:
  1. 作为一种语法糖,它可以让你的代码更易读,至少更少阻塞:x = a().b().c().d() vs x = a.b.c.d
  2. 假设您已经有类似obj.attr 的代码...很多类似的代码,并且在某个时候您意识到在所有这些地方您需要一个函数而不是访问运算符 Get/set 来救援。在调试以捕获属性访问时特别有用。更重要的是,如果您必须使用您无法控制的代码
  3. 有时使用 getter 更为惯用。读者希望obj.attr 没有副作用,但他不确定是否看到了函数

【讨论】:

    猜你喜欢
    • 2015-10-08
    • 2020-12-27
    • 1970-01-01
    • 2013-07-09
    • 2014-04-18
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    相关资源
    最近更新 更多