ECMAScript中有两种属性:数据属性与访问器属性。
[[]]表示内部值
- 数据属性
- [[Enumerable]]:表示能否通过for-in循环属性,默认值为true。
- [[Value]]:包含这个属性的数据值,默认值为undefined。
- 访问器属性
- [[Enumerable]]:表示能否通过for-in循环属性,默认值为true。
我们之前见到的属性大部分都是数据属性。因为一般我们都可以直接访问这些属性的值。而不是在访问时,要调用get函数。
-
Object.defineProperty()
这些属性的特性都是内部值,要想修改属性的特性,必须使用ECMAScript5的Object.defineProperty()
方法。但是支持这个方法的浏览器有IE9+(IE8部分实现)、FireFox 4+、Safari 5+、Opera 12+和Chrome。var person={}; //三个参数:属性所在对象、属性的名字、一个描述符对象 Object.defineProperty(person,"name",{ writable:false, value:"dudu" }); alert(person.name);//dudu person.name="bobo"; alert(person.name); //dudu
【注意】1、对于configurable这个特性一旦设置为false就没有办法在设置为true 2、再调用这个方法时,如果不指定特性的值,那么这些特性就默认为false啦,所以要是用了就指定。
var book={
_year:2004,
edition:1
};
Object.defineProperty(book,"year",{
get:function(){
return this._year;
},
set:function(newvalue){
if(newvalue>2004){
this._year=newvalue;
this.edition+=newvalue-2004;
}
}
});
book.year=2005;
alert(book.edition);
上述代码是用这个方法定义访问器属性。
_year前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性则包含一个getter函数和一个setter函数。
这两个函数并不是必须要写,如果不写则意味着该属性就是不能读不能写。
-
Object.defineProperties
可以定义多个属性。
var book={};
Object.defineProperties(book,{
year:{
value:2004,
writable:false
},
edition:{
value:1,
writable:false
}
}); -
Object.getOwnPropertyDescriptor
读取属性的特性
var descriptor=Object.getOwnPropertyDescriptor(book,"year");
alert(descriptor.value);
alert(descriptor.writable);//fasle
以上三个方法,适用的浏览器版本是相同的。
上篇笔记说创建对象的方法,最终推荐的是封装的原型与构造函数混合的模式。我们在利用一个构造函数实例完一个对象后,其实可以再为他添加属性,可以不添加到原型内。
function Person(){} Person.prototype.name="dudu"; var person1=new Person(); var person2=new Person(); person1.name="xixi"; alert(person1.name);//xixi alert(person2.name);//dudu
利用上面的代码来解释一下下面几个原理以及方法。
-
instanceof
确定该实例是否属于该自定义类型
alert(person1 instanceof Person); -
isprototypeof()
虽然所有实现中无法访问到[[prototype]],但可以通过isprototypeof()
方法,来判断对象实例与原型对象之间的关系是否存在。
alert(Person.prototype.isPrototypeOf(person1));//true -
hasOwnProperty()
alert(person1.hasOwnProperty("name"));//true
alert(person2.hasOwnProperty("name"));//false
这个属性时用来检测“name”属性是否属于person1这个实例对象的实例中。该函数在执行属性查找的时候,永远不会查找原型。
关于上面的结果一个true一个false,是由原因的。
每当代码读取某个对象的属性时,都会执行一次搜索,目标是具有给定名字的属性。
搜索首先从对象实例本身开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值,如果没有,则继续搜索该实例对象内指针指向的原型。
所以person1.name="xixi";
这句代码并不是覆盖了原型,而是在person1实例中添加了一个属性。 -
in
alert("name" in person1)
无论属性存在于实例中还是原型中,只要存在,就返回true。
枚举对象的属性
-
for-in
在使用这个循环时,返回的是所有能够通过对象访问的,可枚举的属性。
构造函数的属性,原型属性是不可枚举的。
如果该属性是被重写的,那么默认该属性为可以枚举的,且这个属性也可以被for—in循环访问到。
var obj={
toString : function(){
return "My Object";
}
};
for (var prop in obj){
if (prop=="toString"){
alert("found toString");
//IE8以前版本不显示,屏蔽了不可枚举的属性名
}
} -
object.keys
取得对象上所有可枚举属性
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=["bobo","xixi"];
//
if(typeof this.sayName!= "function")
{
Person.prototype.sayNmae=function(){
alert(this.name);
};
}
}
var person=new Person("dudu",12,"painter")
var keys=Object.keys(Person.prototype);//返回原型中的可枚举属性
alert(keys);//sayName
var keyss=Object.keys(person);//返回实例中的可枚举属性
alert(keyss);//name、age、job、friends -
Object.getOwnPropertyNames
取得对象上所有属性,包括不可枚举的
var keysss=Object.getOwnPropertyNames(Person.prototype);
alert(keysss);//constructor、sayName
var keyssss=Object.getOwnPropertyNames(person);
alert(keyssss);//name、age、job、friends