Javascript:为什么 getter 比方法更重要?

Javascript: Why are getters used over methods?

所以我想知道方法和吸气剂之间有什么区别?

正在阅读 Mozilla documentation

Sometimes it is desirable to allow access to a property that returns a dynamically computed value, or you may want to reflect the status of an internal variable without requiring the use of explicit method calls

但他们不是达到了同样的目的吗?为什么一个比另一个好?

为什么说:

var obj = {
    log: ['a', 'b', 'c'],
    get latest() {
    if (this.log.length == 0) {
      return undefined;
    }
    return this.log[this.log.length - 1];
  }
}

console.log(obj.latest);

有时比只使用 latest() 方法并调用 obj.latest() 更可取。如果代码在这两种情况下都是 运行,那有什么意义呢?它们不是都是动态的吗?

文档 also reads:

Getters give you a way to define a property of an object, but they do not calculate the property's value until it is accessed.

'accessed' 和 'called' 到底有什么区别?一个方法在被调用之前不是 运行,就像一个 属性 在它被包含之前不会被访问一样?那么意义在哪里呢?

注意,以下是意见。

A getter 用于检索特定 属性 的值,它允许您的对象具有基于其他属性值的动态属性,但除此之外的行为与您期望的属性一样表现。 getter 允许您定义在访问 属性 时调用的方法,即使您使用普通对象 属性 访问器、myObject.dynamicPropmyObject['dynamicProp'].

吸气剂正是为此目的而提供的。如果这是您正在编写的方法的意图,请使用 getter 语法。

存在一些方法来做其他语言上的、面向行动的事情,而不是简单地return一些属性你正在写的对象。

您总是可以将方法写成 getter,但为什么呢?

所以这取决于你的意图。 Getters 指定意图,如果您的意图是提供一个动态的 属性,它的行为就像一个对象 属性,那么在方法上使用 getter。

希望对您有所帮助!

已更新

虽然这里有技术上的细微差别需要理解,而且我倾向于使用上面的 getters,但我想说,经过进一步思考,你希望采用的方法是给你基于:

(1) 是否要使用普通访问器访问此 属性?您是否接受隐藏某些逻辑的动态属性? (它们本身并没有 'hide' 逻辑,但它们看起来就像调用者的普通道具)。然后使用 get().

(2) 您想使 属性 是动态的这一点显而易见且更易读吗?除了根据该对象现有属性的当前值计算动态 属性 之外,您是否还在做其他事情?您可以明确地调用该方法吗?然后使用一种方法,例如getLatest().

根据 MSDN

Object.defineProperty() 的文档

Property descriptors present in objects come in two main flavors: data descriptors and accessor descriptors. A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.

Both data and accessor descriptors are objects. They share the following optional keys:

configurable true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.

enumerable true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.

A data descriptor also has the following optional keys:

value The value associated with the property. Can be any valid JavaScript value (number, object, function, etc). Defaults to undefined.

writable true if and only if the value associated with the property may be changed with an assignment operator. Defaults to false.

An accessor descriptor also has the following optional keys:

get A function which serves as a getter for the property, or undefined if there is no getter. When the property is accessed, this function is called without arguments and with this set to the object through which the property is accessed (this may not be the object on which the property is defined due to inheritance). The return value will be used as the value of the property. Defaults to undefined.

set A function which serves as a setter for the property, or undefined if there is no setter. When the property is assigned to, this function is called with one argument (the value being assigned to the property) and with this set to the object through which the property is assigned. Defaults to undefined.

If a descriptor has neither of value, writable, get and set keys, it is treated as a data descriptor. If a descriptor has both value or writable and get or set keys, an exception is thrown.

这表示getset分别拦截访问调用和赋值调用。

一个很好的例子(和描述)here 指出了一个清楚的例子,说明它何时有用。

假设您有一个人的名字和姓氏,并且通常需要全名。

person.setLastName('Smith');
person.setFirstName('Jimmy');
person.getFullName(); // Jimmy Smith

使用 getset 键,您可以选择像这样声明对象:

var person = {
    firstName: 'Jimmy',
    lastName: 'Smith',
    get fullName() {
        return this.firstName + ' ' + this.lastName;
    },
    set fullName (name) {
        var words = name.toString().split(' ');
        this.firstName = words[0] || '';
        this.lastName = words[1] || '';
    }
}

并分配它,然后像这样访问它:

person.fullName = 'Jack Franklin';
console.log(person.firstName); // Jack
console.log(person.lastName) // Franklin
console.log(person.fullName) // Jack Franklin

这允许开发人员与全名交互,而不会意外地留下未分配或不正确分配的名字或姓氏。

最后,

use strict 指令将相应地强制对通过 getset 定义的属性进行读写尝试。参见 W3Schools

"use strict";
var obj = {get x() {return 0} };

obj.x = 3.14;            // This will cause an error