译者:@baixiaoji 原文
属性的getters
和setters
这是两种属不同类型的属性。
第一种就是数据的属性。我们已经知道他们是怎样运作的了。实际上,到目前为止我们用过的所有属性都是数据属性。
第二种的属性是有些不同的地方。他是访问器属性(accessor properties)。根本上,他们有设置和获取值的功能,但是从外部代码来看其实和寻常的属性没什么不同。
Getters and setters
访问器属性在代码中的表现形式就是getter
和setter
这两个方法。在一个字面量声明的对象,这两个方法的是用get
和set
表示的。
在读取obj.propName
值的时候,getters
运行了,而给obj.propName
赋值的时候,setter
运行了。
举个例子,现在我们有一个user
的对象,有name
和surname
属性。
现在我们希望有一个fullName
属性,其返回的值应该是「John Smith」。当然,我们不想复制粘贴现有的信息,所以我们可以将其作为一个访问器。
从调用的角度来看,一个访问器属性和平常的属性很像。这就是访问器属性的理念。我们不会把user.fullName
叫做一个函数,我们将看作一个平常的属性:getter在该场景背后默默运行。
目前为止,fullName
只有一个getter。如果我们想去将其赋值时,就像这样user.fullName=
,将会有一个报错。
我们通过给user.fullName
添加一个setter来修复这个错误。
现在我们有一个「虚拟」属性,是一个可读可写的属性,可实际上不存在的属性。
Accessor properties are only accessible with get/set
一个属性可以是数据属性,也可以是一个访问器属性,但不能同时是这两种属性的结合。
一旦将一个属性定义为get prop
或是set prop
,这就是个访问器属性。这样一来,如果想要读这个属性就要有一个geeter,想要给该属性赋值就要有一个setter。
有时候,可能一个属性只有setter或只有getter。这种情况下,属性只能写或是只能读。
Accessor descriptors(访问器描述符)
与数据属性相比较,访问器的描述符有点不同。
对访问器属性而言,没有value
和writable
,将这两个属性代替的是get
和set
方法。
那么一个访问器属性的描述符就有一下四种:
get
— 一个没有参数的方法,在读取该属性的时候运行set
— 一个有一个参数的方法,在该属性赋值的时候运行enumerable
— 和数据属性相同configurable
— 和数据属性相同
举个例子,通过defineProperty
创建一个访问器属性fullName
,同时设置get
和set
这两个描述符。
|
|
再次提醒,一个属性要么设置为访问器属性要么设置为数据属性,不能是这两种的结合。
如果我们尝试同时应用get
和value
在同一个描述器中,将会报错。
|
|
Smarter getters/setters
Getters/setters 可以作为真实属性的容器,已获得对其更多的控制。
举个例子,我们想给user
禁止设置过短的name
属性,我们可以将name
属性存储在一个特殊的属性_name
。并且在setter中过滤分配:
|
|
严格来说,外部的代码可以直接通过user._name
的形式来访问name
。但这里有一个尝试就是:一个属性名由下划线(_
)开始,则该属性是内部的,不容许在对象进行操作。
Using for compatibility
在getters和setters之后有一个好主意:它允许控制一个正常的数据属性并且可以随时进行调整。
举个例子:我们给user
对象设置两个数据属性分别是name
和age
:
|
|
不久过后,有了些变化。我们决定将age
替换为birthday
,因为这样更加便利和准确:
|
|
现在还要使用age
属性的旧代码怎么办?
我们找到所有的地方并修好它们,但如果代码是别人写的那就要费点时间。除此之外,对于user
而言存在age
是一件好事吗?在一些情境下,这就是我们想要的。
给age
增加一个getter
来减缓这个问题:
|
|
现在旧代码同样可以工作了,我们还额外获得了一个不错的属性。