你必须了解的JavaScript中的属性描述对象详解(上)
程序小猿2 人气:0属性描述对象
JavaScript其实支持多种编程范式的,包括函数式编程和面向对象编程:
- JavaScript冲的对象被设计为一组属性无序集合,像是一个嘻哈表,由key和value组成;
- key是一个标识符名称,value可以是任意类型,也可以是其他对象或者函数类型;
- 如果值是一个函数,那么我们可以称之为对象的方法。
所以,属性描述对象的概念就为:JavaScript提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。
下面是属性描述对象的一个例子。
{ value:123, writable:false, enumerable:true, configurable:false, get:undefined, set:undefined }
属性描述对象提供六个元属性。
value
:value
是该属性的属性值,默认为undefined
。writable
:writable
是一个布尔值,表示属性值(value)是否可改变(即是否可改写),默认为true
。enumerable
:enumerable
是一个布尔值,表示该属性是否可遍历,默认为true
。如果设为false
,会使得某些操作(比如for...in
循环、Object.keys()
)跳过该属性。configurable
:configurable
是一个布尔值,表示可配置性,默认为true
。如果设为false
,将阻止某些操作改写属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value
属性除外)。也就是说,configurable
属性控制了属性描述对象的可写性。get
:get
是一个函数,表示该属性的取值函数(getter),默认为undefined
。set
:set
是一个函数,表示该属性的存值函数(setter),默认为undefined
。
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor()
方法可以获取属性描述对象。他的第一个参数是目标对象,第二个参数是一个字符串,对应目标对象的某个属性名。
var obj = (p:'a'}; Object.getOwnPropertyDescriptor(obj,'p') //Object{ value:"a", // writable:true, // enumerable:true, // configurable:true }
上面代码中,Object.getOwnPropertyDescriptor()
方法获取obj.p
的属性描述对象。
注意,Object.getOwnPropertyDescriptor()
方法只能用于对象自身的属性,不能用于继承的属性。
var obj = {p:'a'); Object.getOwnPropertyDescriptor(obj,'toStrng') //undefined
上面代码中,toString
是obj
对象继承的属性,Object.getOwnPropertyDescriptor()
无法获取。
Object.getOwnPropertyNames()
Object.getOwnPropertyNames
方法返回一个数组,成员是参数对象自身的全部属性的属性名,不管该属性是否可遍历。
var obj = Object.defineProperties({},{ p1:{value:1,enumerable:true}, p2:{value:2,enumerable:false} }); Object.getOwnPropertyNames(obj) //["p1","p2"]
上面代码中,obj.p1
是可遍历的,obj.p2
是不可遍历的。Object.getOwnPropertyNames
会将它们都返回。
这跟Object.keys
的行为不同,Object.keys
只返回对象自身的可遍历属性的全部属性名。
Object.keys([])//[] Object.getOwnPropertyNmaes([])//['length'] Object.keys(Object.prototype)// [] Object.getOwnPropertyNames(Object.prototype) //['hasOwmProperty' // 'valueOf', // 'constructor', // 'toLocaleString', // 'isPrototypeOf', // 'propertyIsEnumerable', // 'toString']
上面代码中,数组自身的length
属性是不可遍历的,Object.keys
不会返回该属性。第二个例子Object.prototype
也是一个对象,所有实例对象都会继承它,它自身的属性都是不可遍历的。
Object.defineProperty(),Object.defineProperties()
Object.defineProperty()
方法允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象,它的用法如下。
Object.defineProperty(object,propertyName,attributesObject)
Object.defineProperty
方法接受三个参数,依次如下。
- object:属性所在的对象
- propertyName:字符串,表示属性名
- attributesObject:属性描述对象
举例来说,定义obj.p
可以写成下面这样。
var obj = Object.defineProperty({},'p',{ value:123, writable:false, enumerable:true, configurable:false }); obj.p //123 obj.p = 246; obj.p //123
上面代码中,Object.defineProperty()
方法定义了obj.p
属性。由于属性描述对象的writable
属性为false
,所以obj.p
属性不可写。注意,这里的Object.defineProperty
方法的第一个参数是{}
(一个新建的空对象),p
属性直接定义在这个空对象上面,然后返回这个对象,这是Object.defineProperty()
的常见用法。
如果属性已经存在,Object.defineProperty()
方法相当于更新该属性的属性描述对象。
如果一次性定义或修改多个属性,可以使用Object.defineProperties()
方法。
var obj = Object.defineProperties({},{ p1:{value:123,enumerable:true}, p2:{value:'abc',enumerable:true}, p3:{get:function(){return this.p1 + this.p2}, enumerable:true, configurable:true } }); obj.p1 //123 obj.p2 //"abc" obj.p3 //"123abc"
上面代码中,Object.defineProperties()
同时定义了obj
对象的三个属性。其中,p3
属性定义了取值函数get
,即每次读取该属性,都会调用这个取值函数。
注意,一旦定义了取值函数get
(或存值函数set
),就不能将writable
属性设为true
,或者同时定义value
属性,否则会报错。
var obj = {}; Object.defineProperty(obj,'p',{ value:123, get:function(){return 456;} }); //TypeError: Invalid property. // A property cannot both have accessors and be writable or have a value Object.defineProperty(obj,'p'{ writable:true, get:function(){return 456;} }); // TypeError: Invalid property descriptor. // Cannot both specify accessors and a value or writable attribute
上面代码中,同时定义了get
属性和value
属性,以及将writable
属性设为true
,就会报错。
Object.defineProperty()
和Object.defineProperties()
参数里面的属性描述对象,writable
、configurable
、enumerable
这三个属性的默认值都为false
。
var obj = {}; Object.defineProperty(obj,'foo',{}); Object.getOwnPropertyDescriptor(obj,'foo') //{ // value:undefined, // writable:false, // enumerable:false, // configurable:false //}
上面代码中,定义obj.foo
时用了一个空的属性描述对象,就可以看到各个元属性的默认值。
Object.prototype.propertyIsEnumerable()
实例对象的propertyIsEnumerable()
方法返回一个布尔值,用来判断某个属性是否可遍历。注意,这个方法只能用于判断对象自身的属性,对于继承的属性一律返回false
。
var obj = {}; obj.p = 123; obj.propertyIsEnumerable('p') //true obj.propertyIsEnumerable('toString') //false
上面代码中,obj.p
是可遍历的,而obj.toString
是继承的属性。
加载全部内容