var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false }); console.log(person.name);//zhuzhenwei delete person.name; console.log(person.name);//zhuzhenwei
这里我们将新建的属性name的特性设置为了configurable:false;因此下面删除属性的操作是无效的。根据b,可知configurable,默认就是false,即使去掉也不可修改。
d
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//zhuzhenwei delete person.name; console.log(person.name);//undefined
在这里我将默认的configurable的值由默认的false修改为了true,于是变成了可配置的,那么最后就成功删除了。
e
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false }); console.log(person.name);//zhuzhenwei Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
如果之前已经设置成为了false,那么后面再改成true也是徒劳的,即:一旦把属性设置成为不可配置的,就不能再把它变回可配置了。
f
console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…) var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", }); console.log(person.name);//zhuzhenwei Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
这里可以说明,即使前一步我们不管默认的configurable:false,后面得到的仍是不可配置。于是,可以得出结论,为了可配置,必须在第一次调用Object.defineProperty()函数时就将默认的值修改为true。
2.访问器属性及其特性
之前提到,访问器属性不包含数据值,他们包含一对getter函数和setter函数(这两个函数不是必须的)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性是,会调用setter函数并传入新值,这个函数负责决定如何处理数据。同样,由于不能通过JavaScript来直接访问得到访问器属性的特性,所以下面列出的特性将由[[]]括起来以作区分。
[[Configurable]]:默认值为true,a、表示能否通过delete删除属性从而重新定义属性 b、能否修改属性的特性 c、能够把属性由访问器属性修改为数据属性
[[Enumerable]]:默认值为true,表示能否通过for-in循环返回该属性(所以:如果为false,那么for-in循环没法枚举它所在的属性)
[[Get]]:在读取属性时调用的函数。默认值为undefined 关键:特性可以是一个函数
[[Set]]: 在写入属性时调用的函数。默认值为undefined 关键:特性可以是一个函数 由于get和set函数也属于属性的特性,那么他们就有可能(说有可能是因为这两个函数也不是必须的)出现在Object.defineproperty的第三个参数描述符对象的属性中。
注意:1.相对于数据属性,我们发现访问器属性中没有writable特性和value特性。这是因为访问器属性不包含数据值,那么我们怎么当然就不可修改属性的值(用不到writable特性),更不用考虑value了。
2.访问器属性不能直接定义,必须是用Object.defineProperty()来定义。(通过这个规定我们就能准确地判断出访问器属性和数据属性了)
通过下面这个例子来深入理解:
var book={ _year:2004, edition:1 }; Object.defineProperty(book,"year",{ get:function(){<br> return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }); book.year=2005; console.log(book.edition);//2
几个需要深入理解的地方:
访问器属性不能直接定义,必须使用Object.defineProperty()来定义,且该属性具有set和ger特性,于是可以判断,_year和edition是数据属性,而year是访问器属性。
我们看到_year这个数据属性前面是以_(下划线)开头的,这个一种常用的记号,用于表示只能通过对象方法访问的属性。从上面的例子中可以看到get相当于描述符对象的一个方法,而_year正是在这个对象方法访问的属性。而edition既可以通过对象方法访问,也可以由对象直接访问。
book.year表示正在读取访问器属性,这时会调用get函数,并返回了2004这个有效的值。
book.year=2005表示写入访问器属性,这时会调用set函数并传入新值,即将2005传给newValue,这个函数决定如何处理数据。
这时使用访问器属性的常见方法-即设置一个属性的值会导致其他属性发生变化。
3.如何利用Object.defineProperties()方法定义多个特性