JavaScript對象和屬性分析,面向對象(Object-Oriented,OO)的語言有一個標志,那就是它們都有類的概念,而通過類可以創建任意多個具有相同屬性和方法的對象。ECMA-262把對象定義為:“無序屬性的集合,其屬性可以包含基本值、對象或者函數。”嚴格來講,這就相當於說對象是一組沒有特定順序的值,對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值。
一、理解對象
創建自定義對象的最簡單方式就是創建一個object的實例,然後再為它添加屬性和方法,如下所示:
[javascript]view plaincopy
varperson=newObject();
person.name='MyName';
person.age=18;
person.getName=function(){
returnthis.name;
}
早期的JavaScript開發人員經常使用這個模式創建新對象,幾年後,對象字面量成為創建這種對象的首選模式。(比較清楚的查找對象包含的屬性及方法)
[javascript]view plaincopy
varperson={
name:'Myname',
age:18,
getName:function(){
returnthis.name;
}
}[javascript]view plaincopy
varobj=Object.create({x:1});
obj.x//1
typeofobj.toString//"function"
obj.hasOwnProperty('x');//false
varobj=Object.create(null);
obj.toString//undefined[javascript]view plaincopy
varperson={age:28,title:'fe'};
deleteperson.age;//true
deleteperson['title'];//true
person.age;//undefined
deleteperson.age;//true
deleteObject.prototype;//false,
vardescriptor=Object.getOwnPropertyDescriptor(Object,'prototype');
descriptor.configurable;//false
//刪除全局變量
varglobalVal=1;
deleteglobalVal;//false
//刪除局部變量
(function(){
varlocalVal=1;
returndeletelocalVal;
}());//false
//刪除函數聲明
functionfd(){}
deletefd;//false
(function(){
functionfd(){};
returndeletefd;
}());//false
//刪除隱式全局變量
ohNo=1;
window.ohNo;//1
deleteohNo;//true 對象標簽和對象序列化:[javascript]view plaincopy
vartoString=Object.prototype.toString;
functiongetType(o){returntoString.call(o).slice(8,-1);};
toString.call(null);//"[objectNull]"
getType(null);//"Null"
getType(undefined);//"Undefined"
getType(1);//"Number"
getType(newNumber(1));//"Number"
typeofnewNumber(1);//"object"
getType(true);//"Boolean"
getType(newBoolean(true));//"Boolean" (2)、extensible標簽 [javascript]view plaincopy
varobj={x:1,y:2};
Object.isExtensible(obj);//true
Object.preventExtensions(obj);
Object.isExtensible(obj);//false
obj.z=1;
obj.z;//undefined,addnewpropertyfailed
Object.getOwnPropertyDescriptor(obj,'x');
//Object{value:1,writable:true,enumerable:true,configurable:true}
Object.seal(obj);
Object.getOwnPropertyDescriptor(obj,'x');
//Object{value:1,writable:true,enumerable:true,configurable:false}
Object.isSealed(obj);//true
Object.freeze(obj);
Object.getOwnPropertyDescriptor(obj,'x');
//Object{value:1,writable:false,enumerable:true,configurable:false}
Object.isFrozen(obj);//true
//[caution]notaffectsprototypechain!!! (3)、序列化 [javascript]view plaincopy
varobj={x:1,y:true,z:[1,2,3],nullVal:null};
JSON.stringify(obj);//"{"x":1,"y":true,"z":[1,2,3],"nullVal":null}"
obj={val:undefined,a:NaN,b:Infinity,c:newDate()};
JSON.stringify(obj);//"{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}"
obj=JSON.parse('{"x":1}');
obj.x;//1 (4)、自定義序列化 [javascript]view plaincopy
varobj={
x:1,
y:2,
o:{
o1:1,
o2:2,
toJSON:function(){
returnthis.o1+this.o2;
}
}
};
JSON.stringify(obj);//"{"x":1,"y":2,"o":3}"
二、屬性類型
ECMA-262第5版定義隻有內部采用的特性(attribute)時,描述瞭屬性(property)的各種特征。ECMA-262定義這些特性是為瞭實現JavaScript引擎用的,因此JavaScript中不能直接訪問它們。為瞭表示特性是內部值,該規范把它們放在瞭兩對兒方括號中,例如[[Enumerable]].
ECMAScript中有兩種屬性:數據屬性和訪問器屬性
1、數據屬性:
數據屬性指包含一個數據值的位置,可在該位置讀取或寫入值,該屬性有4個供述其行為的特性:
[[configurable]]:表示能否使用delete操作符刪除從而重新定義,或能否修改為訪問器屬性。默認為true;
[[Enumberable]]:表示是否可通過for-in循環返回屬性。默認true;
[[Writable]]:表示是否可修改屬性的值。默認true;
[[Value]]:包含該屬性的數據值。讀取/寫入都是該值。默認為undefined;如上面實例對象person中定義瞭name屬性,其值為’My name’,對該值的修改都反正在這個位置。
要修改對象屬性的默認特征(默認都為true),可調用Object.defineProperty()方法,它接收三個參數:屬性所在對象、屬性名和一個描述符對象(必須是:configurable、enumberable、writable和value,可設置一個或多個值)。可以修改對應的特性值。例如:瀏覽器支持:IE9+、Firefox 4+、Chrome、Safari5+)
[javascript]view plaincopy
varperson={};
Object.defineProperty(person,'name',{
configurable:false,
writable:false,
value:'Jack'
});
alert(person.name);//Jack
deleteperson.name;
person.name='lily';
alert(person.name);//Jack
可以看出,delete及重置person.name的值都沒有生效,這就是因為調用defineProperty函數修改瞭對象屬性的特征;值得註意的是一旦將configurable設置為false,則無法再使用defineProperty將其修改為true(執行會報錯:can't redefine non-configurable property);在調用Object.defineProperty()方法時,如果不指定,configurable、enumberable和writable特性默認值都是false。
2、訪問器屬性:
它主要包括一對getter和setter函數,在讀取訪問器屬性時,會調用getter返回有效值;寫入訪問器屬性時,調用setter,寫入新值;該屬性有以下4個特征:
[[Configurable]]:是否可通過delete操作符刪除重新定義屬性;
[[Numberable]]:是否可通過for-in循環查找該屬性;
[[Get]]:讀取屬性時調用,默認:undefined;
[[Set]]:寫入屬性時調用,默認:undefined;
訪問器屬性不能直接定義,必須使用defineProperty()來定義,如下:
[javascript]view plaincopy
varperson={
_age:18
};
Object.defineProperty(person,'isAdult',{
get:function(){
if(this._age>=18){
returntrue;
}else{
returnfalse;
}
}
});
alert(person.isAdult?'成年':'未成年');//成年[javascript]view plaincopy
Object.defineProperties(person,{
title:{value:'fe',enumerable:true},
corp:{value:'BABA',enumerable:true},
salary:{value:50000,enumerable:true,writable:true},
luck:{
get:function(){
returnMath.random()>0.5?'good':'bad';
}
},
promote:{
set:function(level){
this.salary*=1+level*0.1;
}
}
});
Object.getOwnPropertyDescriptor(person,'salary');
//Object{value:50000,writable:true,enumerable:true,configurable:false}
Object.getOwnPropertyDescriptor(person,'corp');
//Object{value:"BABA",writable:false,enumerable:true,configurable:false}
person.salary;//50000
person.promote=2;
使用Object.getOwnPropertyDescriptor()方法可以取得給定屬性的特性,這個方法接收兩個參數:屬性所在的對象和要讀取其描述的屬性名稱。返回值是一個對象,如果是訪問器屬性,這個對象的屬性有configurable,enumberable,
屬性getter/setter方法實例:
[javascript]view plaincopy
varman={
name:'Bosn',
weibo:'@Bosn',
getage(){
returnnewDate().getFullYear()-1988;
},
setage(val){
console.log('Agecan\'tbesetto'+val);
}
}
console.log(man.age);//27
man.age=100;//Agecan'tbesetto100
console.log(man.age);//still27
[javascript]view plaincopy
varman={
weibo:'@Bosn',
$age:null,
getage(){
if(this.$age==undefined){
returnnewDate().getFullYear()-1988;
}else{
returnthis.$age;
}
},
setage(val){
val=+val;
if(!isNaN(val)&&val>0&&val<150){
this.$age=+val;
}else{
thrownewError('Incorrectval='+val);
}
}
}
console.log(man.age);//27
man.age=100;
console.log(man.age);//100;
man.age='abc';//error:Incorrectval=NaN
[javascript]view plaincopy
functionfoo(){}
Object.defineProperty(foo.prototype,'z',{
get:function(){
return1;
}
});
varobj=newfoo();
obj.z;//1
obj.z=10;
obj.z;//still1
Object.defineProperty(obj,'z',{
value:100,configurable:true
}
);
obj.z;//100;
deleteobj.z;
obj.z;//backto1
varo={};
Object.defineProperty(o,'x',{value:1});//writable=false,configurable=false
varobj=Object.create(o);
obj.x;//1
obj.x=200;
obj.x;//still1,can'tchangeit
Object.defineProperty(obj,'x',{writable:true,configurable:true,value:100});
obj.x;//100
obj.x=500;
obj.x;//500[javascript]view plaincopy
vardescriptor=Object.getOwnPropertyDescriptor(person,'_age');
alert(descriptor.value);//19
alert(descriptor.configurable);//false
alert(typeofdescriptor.get);//undefined