ECMA5规定了只有内部才有的特性,描述了属性的各种特征,这些特性用于实现JavaScript引擎,因此在Js中不能直接访问他们。为了标识特性,我们一般会他们放入两对方括号中。
ECMAScript中有两种属性:数据属性、访问器属性,其中访问器属性不能直接定义,而是通过Object.defineProperty()方法来定义创建,下面会讲这种方法。
需要修改属性默认的特性,则要用到Object.defineProperty()方法了。
Object.defineProperty(属性所在对象,属性名字,描述符对象):其中描述符对象的属性包括configurable、enumerable、writable、value,可修改其中的一或多个属性来修改对应的特性值。
此方法在IE8中只能在DOM对象上使用,而且只能创建访问器属性。(部分实现)
完全实现这个方法的浏览器有:IE9+、Firefox 4+、Safari 5+、Opera 12+、Chrome。
*configurable、enumerable、writable这三个属性若不指定,则默认为false。
var person={}; Object.defineProperty(person,'name',{ value:'a' }); delete person.name; alert(person.name);//a
var person2={}; Object.defineProperty(person2,'name',{ configurable:true, value:'a' }); delete person2.name; alert(person2.name);//undefined
若将configurable设置为false之后,再设置它为true是无效的。一旦把属性定义为不可配置的,就不能再把它变回可配置的了。
其他两个属性的使用如下:
var person={}; Object.defineProperty(person,'name',{ writable:false, value:'a' }); alert(person.name);//a person.name='b'; alert(person.name);//a Object.defineProperty(person,'name',{ enumerable:false }); for(var prop in person){ alert(prop);//不显示 }
访问器属性的常见使用方式:设置一个属性的值导致其他属性发生变化:
var book={ _year:2004,//_标记着只能通过对象方法访问的属性 edition:1 }; Object.defineProperty(book,'year',{ get:function(){ return this._year; }, set:function(newVal){ if(newVal>2004){ this._year=newVal; this.edition+=newVal-2004; } } }); book.year=2005; alert(book.edition);//2
除了Object.defineProperty()方法还有Object.defineProperties()方法可以定义多个属性,语法如下:
Object.defineProperties(属性所在对象,{属性1:{描述符对象},{属性2:{描述符对象}}......})
那么要如何获取属性的描述符呢?
Object.getOwnPropertyDescriptor()方法就能做到,语法如下:
Object.getOwnPropertyDescriptor(属性所在的对象,要读取其描述符的属性名称):返回描述符对象。
var person={}; Object.defineProperty(person,'name',{ writable:false, value:'a' }); var discriptor=Object.getOwnPropertyDescriptor(person,'name'); alert(discriptor.writable);//false alert(discriptor.value);//'a'
原型对象.isPrototypeOf(实例对象):判断实例对象的原型是不是这个原型对象
Object.getPrototypeOf(实例对象):根据实例对象获得原型对象
function Person(){ } Person.prototype.name='a'; Person.prototype.sayName=function(){ alert(this.name); } var p1=new Person(); var p2=new Object(); alert(Person.prototype.isPrototypeOf(p1));//true alert(Person.prototype.isPrototypeOf(p2));//false alert(Object.getPrototypeOf(p1));//Object object(Person也是Object,所以会返回Object) alert(Object.getPrototypeOf(p2));//Object object alert(Object.getPrototypeOf(p1)==Person.prototype);//true alert(Object.getPrototypeOf(p1).name);//'a' alert(Object.getPrototypeOf(p2)==Person.prototype);//false
实例对象.hasOwnProperty(属性):检测一个属性是存在于实例中,还是存在于原型中。若存在于实例中,则返回true。
function Person(){ } Person.prototype.name='a'; Person.prototype.sayName=function(){ alert(this.name); } var p1=new Person(); var p2=new Person(); p2.name='b'; alert(p1.hasOwnProperty('name'));//false alert(p2.hasOwnProperty('name'));//true
但是上面的方法若是遇到不存在于原型对象也不存在于实例对象中的属性也返回false,这样就不好判断是不是存在于原型对象中,所以就要用到In操作符了。
in操作符:在通过对象能访问给定属性时返回true,无论在实例对象还是原型对象中。
结合in操作符,我们可以定义一个检测属性位于实例对象还是原型对象中的方法:
function Person(){ } Person.prototype.name='a'; Person.prototype.sayName=function(){ alert(this.name); } var p1=new Person(); var p2=new Person(); p2.name='b'; alert(hasPrototypeProperty(p1,'name'));//true alert(hasPrototypeProperty(p2,'name'));//false function hasPrototypeProperty(obj,attr){ return !obj.hasOwnProperty(attr)&&(attr in obj); }
Object.keys(对象):返回一个包含所有可枚举属性的字符串数组。
Object.getOwnPropertyNames(对象):返回所有属性,包括了不可枚举的属性。
function Person(){ } Person.prototype.name='a'; Person.prototype.sayName=function(){ alert(this.name); } alert(Object.keys(Person.prototype));//name,sayName alert(Object.getOwnPropertyNames(Person.prototype));//constructor,name,sayName
*注:constructor和prototype属性的[[Enumerable]]默认为false。
支持这两个方法的浏览器:IE 9+、Firefox 4+、Safari 5+、Opera 12+、Chrome。