属性类型

属性类型

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}
posted @   菜鸡又来了  阅读(212)  评论(0)    收藏  举报
点击右上角即可分享
微信分享提示