属性类型

  • A+
所属分类:Web前端
摘要

ES5定义了内部才用的特性时,描述了属性的各种特征。ES5定义这些特征是为了实现 JavaScript 引擎用的,因此在 JavaScript 中不能直接访问它们。为了表示特性时内部值,该规范把他们放在了两对中括号中,例如 [[Enumerable]]。


属性类型

ES5定义了内部才用的特性时,描述了属性的各种特征。ES5定义这些特征是为了实现 JavaScript 引擎用的,因此在 JavaScript 中不能直接访问它们。为了表示特性时内部值,该规范把他们放在了两对中括号中,例如 [[Enumerable]]

ECMAScript 中有两种属性:数据属性和访问器属性。

数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性:

特性 描述 默认值
[[Configurable]](可配置的) 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性 true
[[Enumerable]](可枚举的) 表示能否通过 for-in 循环返回属性 true
[[Writable]](可写入的) 表示能否修改属性的值 true
[[Value]](属性值) 包含这个属性的数据值。读取属性值的时候,从这个位置读取 undefined

创建一个 属性name属性值小明student 对象

const student = { 	name: '小明' } 

这里 name 的属性值为 小明, 也就是说 name 的 [[Value]] 特性被设置成 '小明', 而对这个值的任何修改都将反映到这个位置上

要修改属性默认的特性,只能使用 Object.defineProperty() 方法。

这个方法接收三个参数:属性所在的对象,属性名,和配置对象。

其中配置对象的属性值为:

  • configurable
  • enumerable
  • writable
  • value

将对象 student 的属性 name 的特性修改为不可删除的,可以通过 Object.defineProperty() 方法实现:

const student = { 	name: '小明', 	age: 22 } Object.defineProperty(student, 'name', { 	// 默认为true,当值为false时,该属性不可以被 delete 删除 	configurable: false })  delete student.age console.log(student)	// { name: '小明' }  delete student.name		// 严格模式下会抛出错误,非严格模式下会被忽略 console.log(student)	// { name: '小明' } 

将对象 student 的属性 sex 配置为不可被枚举的代码:

const student = { 	name: '小明', 	age: 22, 	sex: '男' } 			 for (const prop in student) { 	console.log(prop)		// name age sex } 			 Object.defineProperty(student, 'sex', { 	enumerable: false }) 			 for (const prop in student) { 	console.log(prop)		// name age } 

将对象 student 的属性 name 改为只读的:

const student = { 	name: '小明' }  Object.defineProperty(student, 'name', { 	writable: false })  student.name = '小红'	// 严格模式下会抛出错误,非严格模式下会被忽略 console.log(student.name)	// 小明 

访问器属性

访问器属性不包含数据值,它们包含一对 gettersetter 函数(它们不是必需的)

在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值

在写入访问器属性时,会调用 setter 函数并传入新的值,这个函数负责决定如何处理数据

访问器属性有以下4个特性:

特性 描述 默认值
[[Configurable]](可配置的) 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性 true
[[Enumerable]] 表示能否通过 for-in 循环返回属 true
[[Get]] 在读取属性时调用的函数 undefined
[[Set]] 在写入属性时调用的函数 undefined

访问器属性的前面时下划线,表示只能通过对象方法访问的属性,下面代码的访问器属性 birthday 中包含了一对 gettersetter 函数。

getter 函数返回 _birthday 的值,setter 函数通过计算来确定正确的版本。因此,把 birthday 属性修改为 '1999/04/22' 会导致 _birthday 变成 '1999/04/22',而 age 变为 22.

这是使用访问器属性的常见方式,即设置一个属性的值会导致其他的属性值发生变化。

const student = { 	name: '小明', 	age: 0, 	_birthday: '' }  Object.defineProperty(student, 'birthday', { 	get: function(){ return this._birthday }, 	set: function(val){ 		this._birthday = val 		this.age = new Date().getFullYear() - new Date(val).getFullYear() 	} })  student.birthday = '1999/04/22'  console.log(student)		// {name: "小明", age: 22, _birthday: "1999/04/22"} 

不一定非要同使指定 gettersetter。 只指定 getter 意味着属性是不能写入的,尝试写入属性会被忽略。在严格模式下,尝试写入指定了 getter 函数的属性会抛出错误。 类似地,只指定 setter 函数的属性页不能读取,否则会抛出 undefine,在严格模式下会抛出错误。

定义多个属性

由于为对象定义多个属性的可能性很大,可以通过 Object.defineProperties() 方法来一次定义多个属性,具体代码如下:

const student = {}  Object.defineProperties(student, { 	name: { 		value: '小明' 		// 以下被注释的代码不写则属性值默认为 false 		// configurable: true, 		// enumerable: true, 		// writable: true 	}, 	age: { 		value: 0, 		writable: true 	}, 	_birthday: { 		value: '', 		writable: true 	}, 	birthday: { 		get: function() { return this._birthday }, 		set: function(val) { 			this._birthday = val 			this.age = new Date().getFullYear - new Date(val).getFullYear() 		} 	} }) 	 student.birthday = '1999/04/22' console.log(student)	// {name: "小明", age: NaN, _birthday: "1999/04/22"} 

读取属性的特性

想要读取属性的特性,可以通过 Object.getOwnPropertyDescriptor() 方法,获取 刚才以上的 student 属性特性的代码如下:

const descName = Object.getOwnPropertyDescriptor(student, 'name') console.log(descName) // {value: "小明", writable: false, enumerable: false, configurable: false}  const descAge = Object.getOwnPropertyDescriptor(student, 'age') console.log(descAge) // {value: 22, writable: true, enumerable: false, configurable: false}  const descBirth1 = Object.getOwnPropertyDescriptor(student, 'birthday') console.log(descBirth1) // {get: ƒ, set: ƒ, enumerable: false, configurable: false}  const descBirth2 = Object.getOwnPropertyDescriptor(student, '_birthday') console.log(descBirth2) // {value: "1999/04/22", writable: true, enumerable: false, configurable: false}