对象之JS中的数据属性和访问器属性

对象之JS中的数据属性和访问器属性:

ECMA-262使用一些内部特性来描述属性的特征。这些特性是由为JavaScript实现引擎的规范定义的。因此,开发者不能在JavaScript中直接访问这些特性。为了将某个特性标识为内部特性,规范会用两个中括号把特性的名称括起来,比如[[Enumerable]]。

属性分两种:数据属性访问器属性

一、数据属性:

数据属性包含一个保存数据值的位置。值会从这个位置读取,也会写入到这个位置。数据属性有4个特性描述它们的行为。

❑ [[Configurable]]:表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特性都是true,如前面的例子所示。

❑ [[Enumerable]]:表示属性是否可以通过for-in循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是true,如前面的例子所示。

❑ [[Enumerable]]:表示属性是否可以通过for-in循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是true,如前面的例子所示。

❑ [[Value]]:包含属性实际的值。这就是前面提到的那个读取和写入属性值的位置。这个特性的默认值为undefined。

在像前面例子中那样将属性显式添加到对象之后,[[Configurable]]、[[Enumerable]]和[[Writable]]都会被设置为true,而[[Value]]特性会被设置为指定的值。比如:

let person = {
    name: 'kelly'
}

这里,我们创建了一个名为name的属性,并给它赋予了一个值"kelly"。这意味着[[Value]]特性会被设置为"kelly",之后对这个值的任何修改都会保存这个位置。

要修改属性的默认特性,就必须使用Object.defineProperty()方法。这个方法接收3个参数:要给其添加属性的对象、属性的名称和一个描述符对象。最后一个参数,即描述符对象上的属性可以包含:configurable、enumerable、writable和value,跟相关特性的名称一一对应。根据要修改的特性,可以设置其中一个或多个值。比如:

在这里插入图片描述
这个例子创建了一个名为name的属性并给它赋予了一个只读的值"kelly"。这个属性的值就不能再修改了,在非严格模式下尝试给这个属性重新赋值会被忽略。在严格模式下,尝试修改只读属性的值会抛出错误。

类似的规则也适用于创建不可配置的属性。比如:
在这里插入图片描述
这个例子把configurable设置为false,意味着这个属性不能从对象上删除。非严格模式下对这个属性调用delete没有效果,严格模式下会抛出错误。此外,一个属性被定义为不可配置之后,就不能再变回可配置的了。再次调用Object.defineProperty()并修改任何非writable属性会导致错误。

因此,虽然可以对同一个属性多次调用Object.defineProperty(),但在把configurable设置为false之后就会受限制了。

在调用Object.defineProperty()时,configurable、enumerable和writable的值,如果不指定,则都默认为false。多数情况下,可能都不需要Object.defineProperty()提供的这些强大的设置,但要理解JavaScript对象,就要理解这些概念。

2、访问器属性

访问器属性不包含数据值。相反,它们包含一个获取(getter)函数和一个设置(setter)函数,不过这两个函数不是必需的。在读取访问器属性时,会调用获取函数,这个函数的责任就是返回一个有效的值。在写入访问器属性时,会调用设置函数并传入新值,这个函数必须决定对数据做出什么修改。访问器属性有4个特性描述它们的行为。

❑ [[Configurable]]:表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性,以及是否可以把它改为数据属性。默认情况下,所有直接定义在对象上的属性的这个特性都是true。

❑ [[Enumerable]]:表示属性是否可以通过for-in循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是true。

❑ [[Get]]:获取函数,在读取属性时调用。默认值为undefined。

❑ [[Set]]:设置函数,在写入属性时调用。默认值为undefined。

访问器属性是不能直接定义的,必须使用Object.defineProperty()。下面是一个例子:

例子中定义一个对象,包含伪私有成员year_和公共成员edition:
在这里插入图片描述
在这个例子中,对象book有两个默认属性:year_和edition。year_中的下划线常用来表示该属性并不希望在对象方法的外部被访问。另一个属性year被定义为一个访问器属性,其中获取函数简单地返回year_的值,而设置函数会做一些计算以决定正确的版本(edition)。因此,把year属性修改为2018会导致year_变成2018, edition变成2。这是访问器属性的典型使用场景,即设置一个属性值会导致一些其他变化发生。

获取函数和设置函数不一定都要定义。只定义获取函数意味着属性是只读的,尝试修改属性会被忽略。在严格模式下,尝试写入只定义了获取函数的属性会抛出错误。类似地,只有一个设置函数的属性是不能读取的,非严格模式下读取会返回undefined,严格模式下会抛出错误。

在不支持Object.defineProperty()的浏览器中没有办法修改[[Configurable]]或[[Enumerable]]。注意 在ECMAScript 5以前,开发者会使用两个非标准的访问创建访问器属性:define-Getter()和__defineSetter__()。这两个方法最早是Firefox引入的,后来Safari、Chrome和Opera也实现了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值