本文内容
1、理解对象;
2、ECMAScript有两种属性类型:数据属性和访问器属性(getter和setter函数);
3、数据属性的属性特性:[[Configurable]]、[[Enumerable]]、[[Writable]]、[[value]];
4、访问器属性的属性特性:[[Configurable]]、[[Enumerable]]、[[get]]、[[set]];
5、Object.defineProperty()、Object.defineProperties()、Object.getOwnPropertyDescriptor()设置或读取属性特性(属性描述符)的方法
理解对象
ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。
也就是说对象是一组没有特定顺序的名值对,一个名字对应一个值,值可以是数据(包括基本值以及引用类型值)和函数,每一个名值对都是这个对象的属性。
var person = {
name: 'youyang',
age: 25,
job: 'coder',
sayName: function() {
console.log(this.name)
}
}
以上代码创建了一名为person的对象,它有四个属性:name、age、job和sayName。注意虽然通常我们说name、age、job为属性,而sayName称作person对象的方法,其实它也是属性,只不过值为函数而已。
属性类型及属性特性
1、首先需要明确javascript对象中有哪些属性类型?
ECMAScript中有两种属性:数据属性和访问器属性。
2、什么是属性特性?
每个对象的属性(包括方法)在创建时都带有一些特征值,ECMA-262定义这些特性值是为了实现javascript引擎用的,即内部使用的,所以该规范把它们放在两对方括号中:如[[Enumerable]]。
3、那么属性都有哪些描述行为的特性呢?不同的属性类型的属性特性又有什么不同呢?
数据属性
数据属性有四个描述其行为的特性:
- [[configurable]]:表示能否通过delete关键字删除属性从而重新定义属性,能否修改属性的特性(包括[[configurable]]特性本身以及下面三个其他特性),或者能否把属性修改为访问器属性。像上面例子中那样直接定义在对象上的属性默认值为true.
- [[Enumerable]]:是否可枚举(for-in循环中能否返回该属性),上面那样直接定义在对象上的属性默认值为true。
- [[Writable]]:是否可修改属性的值,默认为true;
- [[value]]:对应属性值,读取的时候从这里读取,写入的时候将新值保存在这里,默认值为undefined;
var obj = {
num: 10
}
这里创建了一个名为num的属性,它的 [[configurable]]、 [[Enumerable]]、 [[Writable]]均为true,而[[value]]为10。
访问器属性
相比数据属性,访问器属性没有[[value]]这一属性特性,而是拥有一对函数:getter()和setter(),在读取访问器属性的时候,调用getter(),该函数负责返回有效的值,在写入即设置属性的值的时候调用setter()并传入新值,由setter()负责执行处理数据的操作。
访问器属性包含4个属性特性:
- [[configurable]]:表示能否通过delete删除属性,能否修改属性的特性(包括[[configurable]]特性本身以及下面三个其他特性),或者能否把属性修改为数据属性。直接定义在对象上的属性默认值为true;
- [[Enumerable]]:是否可枚举(for-in循环中能否返回该属性),上面那样直接定义在对象上的属性默认值为true;
- [[Get]]:在读取属性时调用的函数,默认为undefined;
- [[Set]]:在写入属性时调用的函数,默认为undefined。
Object.defineProperty()
这个方法有两个作用,一个是修改属性的默认属性特性,另一个就是定义属性,因为如果你想在定义一个属性的同时指定它的一些属性特性那么就必须使用这个方法,并且当你想定义一个访问器属性时只能使用Object.defineProperty()来实现,因为访问器属性是不能直接定义的。
此方法接收的参数:对象,指定的属性名称,一个描述符对象(用来设置属性特性的对象)
使用方法如下:
1、要修改一个属性的默认特性
var obj = {
num: 10
}
Object.defineProperty(obj, 'num', {
value: 20,
writable: false
})
console.log(obj.num) // 20
obj.num = 30
console.log(obj.num) // 20
上面的例子中,我们将对象obj的属性num的[[writable]]是否可修改特性设置为了false,于是num属性不能被修改,当尝试为它写入新值(obj.num = 30)时,非严格模式下,此操作会被忽略,严格模式下则会报错。
2、定义访问器属性
访问器属性不能直接定义,必须使用Object.defineProperty()。
var obj = {
num: 10
}
Object.defineProperty(obj, 'data', {
get: function() {
return this.num
},
set: function(newVal) {
if (newVal > 10) {
this.num = newVal
}
}
})
console.log(obj.data) // 10
obj.data = 20
console.log(obj.data) // 20
console.log(obj.num) // 20
getter和setter函数或许你常听说,但是并不知道它们到底是什么,因为我们确实在日常开发中很少有机会用到它们,但是在一些框架的源码中常见到它们的应用。
Object.defineProperties()
与Object.defineProperty()方法相同,Object.defineProperties()方法也有同样作用:设置和修改属性特性,只不过Object.defineProperties()方法可以设置多个属性。
使用方法如下:
var obj = {
num: 10
}
Object.defineProperties(obj, {
name: {
writable: false,
value: '张三'
},
data: {
get: function () {
return this.num
},
set: function (newVal) {
if (newVal > 10) {
this.num = newVal
}
}
}
})
以上代码使用Object.defineProperties()定义了一个数据属性和一个访问器属性。
Object.getOwnPropertyDescriptor()
这个方法的作用就是获取指定属性的属性描述符,所谓属性描述符就是我们之前一直提到的属性特性。
接收两个参数:属性所在对象和指定属性名称
返回值:一个对象,如果是访问器属性,对象的属性包括:configurable,enumerable,get和set,如果是数据属性,则返回的这个对象的属性有:configurable,enumerable,writable,value。
var obj = {
num: 10
}
console.log(Object.getOwnPropertyDescriptor(obj, 'num')) // {value: 10, writable: true, enumerable: true, configurable: true}