对象属性描述符的类型分为两种:数据属性和访问器属性html
数据属性函数
数据属性(data property)包含一个数据值的位置,在这个位置能够读取和写入值。数据属性有4个特性测试
【1】Configurable(可配置性)this
可配置性决定是否可使用delete删除属性,以及是否能够修改属性描述符的特性,默认值为truespa
【2】Enumerable(可枚举性)prototype
可枚举性决定属性是否出如今对象的属性枚举中,好比是否能够经过for-in循环返回该属性,默认值为truecode
【3】Writable(可写性)htm
可写性决定是否能够修改属性的值,默认值为true对象
【4】Value(属性值)blog
属性值包含这个属性的数据值,读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。默认值为undefined
访问器属性
对象属性是名字、值和一组属性描述符构成的。而属性值能够用一个或两个方法替代,这两个方法就是getter和setter。而这种属性类型叫访问器属性(accessor property)
可配置性决定是否可使用delete删除属性,以及是否能够修改属性描述符的特性,默认值为true
可枚举性决定属性是否出如今对象的属性枚举中,好比是否能够经过for-in循环返回该属性,默认值为true
【3】getter
在读取属性时调用的函数。默认值为undefined
【4】setter
在写入属性时调用的函数。默认值为undefined
和数据属性不一样,访问器属性不具备可写性(Writable)。若是属性同时具备getter和setter方法,那么它是一个读/写属性。若是它只有getter方法,那么它是一个只读属性。若是它只有setter方法,那么它是一个只写属性。读取只写属性老是返回undefined
前面介绍了属性描述符,要想设置它们,就须要用到描述符方法。描述符方法总共有如下4个:
【1】Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor(o,name)方法用于查询一个属性的描述符,并以对象的形式返回
查询obj.a属性时,可配置性、可枚举性、可写性都是默认的true,而value是a的属性值1
查询obj.b属性时,由于obj.b属性不存在,该方法返回undefined
var obj = {a:1}; //Object {value: 1, writable: true, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(obj,'a')); //undefined console.log(Object.getOwnPropertyDescriptor(obj,'b'));
【2】Object.defineProperty()
Object.defineProperty(o,name,desc)方法用于建立或配置对象的一个属性的描述符,返回配置后的对象
使用该方法建立或配置对象属性的描述符时,若是不针对该属性进行描述符的配置,则该项描述符默认为false
var obj = {}; //{a:1} console.log(Object.defineProperty(obj,'a',{ value:1, writable: true })); //因为没有配置enumerable和configurable,因此它们的值为false //{value: 1, writable: true, enumerable: false, configurable: false} console.log(Object.getOwnPropertyDescriptor(obj,'a'));
【3】Object.defineProperties()
Object.defineProperty(o,descriptors)方法用于建立或配置对象的多个属性的描述符,返回配置后的对象
var obj = { a:1 }; //{a: 1, b: 2} console.log(Object.defineProperties(obj,{ a:{writable:false}, b:{value:2} })); //{value: 1, writable: false, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(obj,'a')); //{value: 2, writable: false, enumerable: false, configurable: false} console.log(Object.getOwnPropertyDescriptor(obj,'b'));
【4】Object.create()
Object.create(proto,descriptors)方法使用指定的原型和属性来建立一个对象
var o = Object.create(Object.prototype,{ a:{writable: false,value:1,enumerable:true} }); //{value: 1, writable: false, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(obj,'a'));
前面分别介绍了数据属性和访问器属性的描述符,但没有详细说明其含义及使用,接下来逐一进行说明
可写性(writable)
可写性决定是否能够修改属性的值,默认值为true
var o = {a:1}; o.a = 2; console.log(o.a);//2
设置writable:false后,赋值语句会静默失效
var o = {a:1}; Object.defineProperty(o,'a',{ writable:false }); console.log(o.a);//1 //因为设置了writable为false,因此o.a=2这个语句会静默失效 o.a = 2; console.log(o.a);//1 Object.defineProperty(o,'a',{ writable:true }); //因为writable设置为true,因此o.a能够被修改成2 o.a = 2; console.log(o.a);//2
在严格模式下经过赋值语句为writable为false的属性赋值,会提示类型错误TypeError
'use strict'; var o = {a:1}; Object.defineProperty(o,'a',{ writable:false }); //Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>' o.a = 2;
[注意]设置writable:false后,经过Object.defineProperty()方法改变属性value的值不会受影响,由于这也意味着在重置writable的属性值为false
var o = {a:1}; Object.defineProperty(o,'a',{ writable:false }); console.log(o.a);//1 Object.defineProperty(o,'a',{ value:2 }); console.log(o.a);//2
可配置性(Configurable)
可配置性决定是否可使用delete删除属性,以及是否能够修改属性描述符的特性,默认值为true
【1】设置Configurable:false后,没法使用delete删除属性
var o = {a:1}; Object.defineProperty(o,'a',{ configurable:false }); delete o.a;//false console.log(o.a);//1
在严格模式下删除为configurable为false的属性,会提示类型错误TypeError
'use strict'; var o = {a:1}; Object.defineProperty(o,'a',{ configurable:false }); //Uncaught TypeError: Cannot delete property 'a' of #<Object> delete o.a;
[注意]使用var命令声明变量时,变量的configurable为false
var a = 1; //{value: 1, writable: true, enumerable: true, configurable: false} Object.getOwnPropertyDescriptor(this,'a');
【2】通常地,设置Configurable:false后,将没法再使用defineProperty()方法来修改属性描述符
var o = {a:1}; Object.defineProperty(o,'a',{ configurable:false }); //Uncaught TypeError: Cannot redefine property: a Object.defineProperty(o,'a',{ configurable:true });
有一个例外,设置Configurable:false后,只容许writable的状态从true变为false
var o = {a:1}; Object.defineProperty(o,'a',{ configurable:false, writable:true }); o.a = 2; console.log(o.a);//2 Object.defineProperty(o,'a',{ writable:false }); //因为writable:false生效,对象a的o属性没法修改值,因此o.a=3的赋值语句静默失败 o.a = 3; console.log(o.a);//2
可枚举性(Enumerable)
可枚举性决定属性是否出如今对象的属性枚举中,具体来讲,for-in循环、Object.keys方法、JSON.stringify方法是否会取到该属性
用户定义的普通属性默认是可枚举的,而原生继承的属性默认是不可枚举的
//因为原生继承的属性默认不可枚举,因此只取得自定义的属性a:1 var o = {a:1}; for(var i in o){ console.log(o[i]);//1 }
//因为enumerable被设置为false,在for-in循环中a属性没法被枚举出来 var o = {a:1}; Object.defineProperty(o,'a',{enumerable:false}); for(var i in o){ console.log(o[i]);//undefined }
propertyIsEnumerable()
propertyIsEnumerable()方法用于判断对象的属性是否可枚举
var o = {a:1}; console.log(o.propertyIsEnumerable('a'));//true Object.defineProperty(o,'a',{enumerable:false}); console.log(o.propertyIsEnumerable('a'));//false
get和set
get是一个隐藏函数,在获取属性值时调用。set也是一个隐藏函数,在设置属性值时调用,它们的默认值都是undefined。Object.definedProperty()中的get和set对应于对象字面量中get和set方法
[注意]getter和setter取代了数据属性中的value和writable属性
【1】给只设置get方法,没有设置set方法的对象赋值会静默失败,在严格模式下会报错
var o = { get a(){ return 2; } } console.log(o.a);//2 //因为没有设置set方法,因此o.a=3的赋值语句会静默失败 o.a = 3; console.log(o.a);//2
Object.defineProperty(o,'a',{ get: function(){ return 2; } }) console.log(o.a);//2 //因为没有设置set方法,因此o.a=3的赋值语句会静默失败 o.a = 3; console.log(o.a);//2
在严格模式下,给没有设置set方法的访问器属性赋值会报错
'use strict'; var o = { get a(){ return 2; } } console.log(o.a);//2 //因为没有设置set方法,因此o.a=3的赋值语句会报错 //Uncaught TypeError: Cannot set property a of #<Object> which has only a getter o.a = 3;
'use strict'; Object.defineProperty(o,'a',{ get: function(){ return 2; } }) console.log(o.a);//2 //因为没有设置set方法,因此o.a=3的赋值语句会报错 //Uncaught TypeError: Cannot set property a of #<Object> which has only a getter o.a = 3;
【2】只设置set方法,而不设置get方法,则对象属性值为undefined
var o = { set a(val){ return 2; } } o.a = 1; console.log(o.a);//undefined
Object.defineProperty(o,'a',{ set: function(){ return 2; } }) o.a = 1; console.log(o.a);//undefined
【3】通常地,set和get方法是成对出现的
var o ={ get a(){ return this._a; }, set a(val){ this._a = val*2; } } o.a = 1; console.log(o.a);//2
Object.defineProperty(o,'a',{ get: function(){ return this._a; }, set :function(val){ this._a = val*2; } }) o.a = 1; console.log(o.a);//2
属性描述符只能用来控制对象中一个属性的状态。而若是要控制对象的状态,就要用到下面的6种方法
Object.preventExtensions()(禁止扩展)
Object.preventExtensions()方法使一个对象没法再添加新的属性,并返回当前对象
Object.isExtensible()(测试扩展)
Object.isExtensible()方法用来检测该对象是否能够扩展
var o = {a:1}; console.log(Object.isExtensible(o));//true o.b = 2; console.log(o);//{a: 1, b: 2} console.log(Object.preventExtensions(o));//{a: 1, b: 2} //因为对象o禁止扩展,因此该赋值语句静默失败 o.c = 3; console.log(Object.isExtensible(o));//false console.log(o);//{a: 1, b: 2}
在严格模式下,给禁止扩展的对象添加属性会报TypeError错误
'use strict'; var o = {a:1}; console.log(Object.preventExtensions(o));//{a:1} //Uncaught TypeError: Can't add property c, object is not extensible o.c = 3;
Object.preventExtensions()方法并不改变对象中属性的描述符状态
var o = {a:1}; //{value: 1, writable: true, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(o,'a')); Object.preventExtensions(o); //{value: 1, writable: true, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(o,'a'));
Object.seal()(对象封印)
对象封印又叫对象密封,使一个对象不可扩展而且全部属性不可配置,并返回当前对象
Object.isSealed()(测试封印)
Object.isSealed()方法用来检测该方法是否被封印
var o = {a:1,b:2}; console.log(Object.isSealed(o));//false console.log(Object.seal(o));//{a:1,b:2} console.log(Object.isSealed(o));//true console.log(delete o.b);//false o.c = 3; console.log(o);//{a:1,b:2}
在严格模式下,删除旧属性或添加新属性都会报错
'use strict'; var o = {a:1,b:2}; console.log(Object.seal(o));//{a:1,b:2} //Uncaught TypeError: Cannot delete property 'b' of #<Object> delete o.b;
这个方法实际上会在现有对象上调用Object.preventExtensions()方法,并把全部现有属性的configurable描述符置为false
var o = {a:1,b:2}; //{value: 1, writable: true, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(o,'a')); console.log(Object.seal(o));//{a:1,b:2} //{value: 1, writable: true, enumerable: true, configurable: false} console.log(Object.getOwnPropertyDescriptor(o,'a'));
Object.freeze()(对象冻结)
Object.freeze()方法使一个对象不可扩展,不可配置,也不可改写,变成一个仅能够枚举的只读常量,并返回当前对象
Object.isFrozen()(检测冻结)
Object.isFrozen()方法用来检测一个对象是否被冻结
var o = {a:1,b:2}; console.log(Object.isFrozen(o));//false console.log(Object.freeze(o));//{a:1,b:2} console.log(Object.isFrozen(o));//true o.a = 3; console.log(o);//{a:1,b:2}
在严格模式下,删除旧属性、添加新属性、更改现有属性都会报错
'use strict'; var o = {a:1,b:2}; console.log(Object.freeze(o));//{a:1,b:2} //Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>' o.a = 3;
这个方法实际上会在现有对象上调用Object.seal()方法,并把全部现有属性的writable描述符置为false
var o = {a:1}; //{value: 1, writable: true, enumerable: true, configurable: true} console.log(Object.getOwnPropertyDescriptor(o,'a')); console.log(Object.freeze(o));//{a:1} //{value: 1, writable: false, enumerable: true, configurable: false} console.log(Object.getOwnPropertyDescriptor(o,'a'));