6.JavaScript物件
物件
JavaScript中的物件是由鍵值對組成,每個鍵值對可以稱為屬性,靜態資料屬性包括名字和四個特性,存取器屬性則略有不同,物件本身也有三個屬性,分別是原型屬性,類屬性以及可拓展屬性,Object.prototype中存有一些可供所有物件使用的方法,如toString(),valueOf()等
物件是JavaScript的基本資料型別,物件可以看成是屬性的無序集合,每個屬性都是一個鍵值對,屬性名通常是字串,因此我們可以物件看成是從字串到值的對映.然而物件不僅僅是字串到值的對映,還可以從一個稱為原型的物件繼承屬性.
物件的屬性包括名字和值,屬性名可以是包含空字串在內的任意字串,但屬性名不能同名
每個屬性還有一些與之相關的值,稱為屬性特性(這些特性是可以加以配置的):
- 可寫,表明是否可以設定該屬性的值
- 可列舉,表明是否可以通過for/in迴圈返回該屬性
- 可配置,表明是否可以刪除或修改屬性
除了包含屬性之外,每個物件還有相關的物件特性:
- 物件的原型指向另一個物件,本物件的屬性繼承自它的原型物件
- 物件的類是一個標識物件型別的字串
- 物件的拓展標記指明瞭是否可以向該物件新增新屬性
建立物件
1.直接使用物件直接量
物件直接量是由若干鍵值對組成的對映表,鍵值對中間使用冒號,每對鍵值對用逗號分隔,整個對映表用花括號括起來.
物件直接量是一個表示式,表示式每次運算都建立並初始化一個新的物件
var empty = {};
var point = {
x:0,
y:1
};
2.通過new建立物件
new運算子建立並初始化一個新物件.關鍵字new後跟隨一個函式呼叫,這個函式稱為建構函式(constructor),建構函式用以初始化一個新建立的物件.
var o = new Object();
var a = new Array();
var b = new Date();
var c = new RegExp("js")
3.原型
每一個除null外的物件都與另一個物件相關聯,另一個物件就叫做原型.
所有通過物件直接量建立的物件都具有同一個原型物件
Object.prototype是沒有原型的,Date等建構函式都有繼承自Object.prototype的原型,如Date.prototype的屬性繼承自Object.prototype
4.Object.create()
Object.create()將建立一個新物件,第一個引數是這個物件的原型,第二個引數用以對物件的屬性進行進一步描述
可以用Object.create(Object.prototype)來建立一個新的空物件
function inherit(p){
if(p===null) throw TypeError();
var t = typeof p;
if(t!=='object' && t!=='function') throw TypeError();
function f(){};
f.prototype = p;
return new f();
}
屬性的查詢和設定
var name = author.name;
var name = author["name"]
以上兩種方法進行查詢,也可直接設定屬性
第二種方式看起來更像陣列,但索引變成了字串索引,這種陣列就是所說的關聯陣列,也叫雜湊,對映或字典,JavaScript物件都是關聯陣列.
假如要查詢一個物件的屬性,如果當前物件不存在,則會在物件的原型物件中查詢,還不存在就接著往上查詢直到找到這個屬性或者查詢到一個原型是null的物件為止
在JavaScript中,只有查詢才會體會到繼承的存在,而設定屬性與繼承無關
屬性的刪除
delete運算子可以刪除物件的屬性,但delete不可以刪除那些可配置性為false的屬性(比如變數宣告和函式宣告的全域性函式)
o = {x:1};
delete o.x;//刪除成功
delete o.x;//不存在,什麼也不做 返回true
delete o.toString;//同上
檢測屬性
判斷某個屬性是否存在於某個物件中,可以通過in運算子、hasOwnProperty()和propertyIsEnumerable()方法實現.
var o = {x:1};
"x" in o; //ture
"y" in o; //false
"toString" in o //true,繼承
hasOwnProperty()用於檢測給定的名字是否是物件的自有屬性.但對於繼承屬性返回false
var o = {x:1};
o.hasOwnProperty("x"); //true
o.hasOwnProperty("y"); //false
o.hasOwnProperty("toString") //false
propertyIsEnumerable()相當於hasOwnProperty()的增強版,它只檢測是自由屬性請可列舉的的屬性
除了這些方法還可以用!來判斷,比如o.x ! undefined
列舉屬性
之前提到的for/in迴圈遍歷物件中所有可列舉的屬性(包括自有屬性和繼承屬性),把屬性名稱賦值給迴圈變數.所有為了避免繼承的影響,通常會這樣
for(p in o){
if(!o.hasOwnProperty(p)) continue; //跳過繼承的屬性
}
for(p in o){
if(typeof o[p] === "function") continue //跳過方法
}
此外還有Object.keys(),它返回一個數組,這個陣列由可列舉的自有屬性的名稱組成,還有一個列舉屬性的函式是Object.hasOwnPropertyNames(),它和上一個函式類似,但它返回物件的所有自有屬性的名稱
setter和getter
物件的屬性值可以有一兩個方法替代,這兩個方法就是getter和setter,由這兩個方法定義的屬性就是"存取器屬性"
var o = {
data_prop: value,//普通屬性
get accessor_prop(){},
set accessor_prop(value){}
}
屬性的特性
屬性除了包含名字和值外,還包含一些可寫,可列舉,可配置的特性.一般可以把資料屬性看成是一個名字和四個特性,資料屬性的四個特性是它的值,可寫性,可列舉性和可配置性.存取器屬性不具有值特性和可寫性,它的可寫性由setter存在與否決定,因此存取器屬性的四個特性是讀取,寫入,可列舉,可配置.
通過呼叫Object.getOwnPropertyDescriptor()可以獲得某個物件特定屬性的屬性描述符
Object.getOwnPropertyDescriptor({x:1},"x")
//返回 {value:1,writable:true,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor(random,"octet")
//返回 {setter:undefined,getter:/*func*/,enumerable:true,configurable:true}
Object.getOwnPropertyDescriptor({},"x")
//不存在,返回undefined
如果想要設定屬性特性,或想讓新建屬性具有某特性,則要呼叫Object.defineProperty(),傳入要修改的物件,要建立或修改的屬性的名稱以及屬性描述符物件
var o = {};
Object.defineProperty(o,"x",{
value: 1,
writable: true,
enumerable: false,//不可列舉
configurable: true
})
o.x; //1
Object.keys(o); //[]不可列舉
Object.defineProperty(o,"x",{writable: false})//無法修改值
Object.defineProperty(o,"x",{get: function(){return 0}})
//將x從資料屬性修改成存取器屬性
o.x; //0
物件的三個屬性
原型屬性
物件的原型屬性是用來繼承屬性的,簡稱為原型.原型屬性是在例項物件建立之初就設定好的,
通過物件直接量建立的物件使用Object.prototype做為原型,通過new函式建立的物件則用建構函式的prototype屬性作為原型,前兩項其實都是建構函式constructor屬性的prototype作為原型,Object.create()使用傳入的引數作為原型
想檢測一個物件是否是另一個物件的原型可以用isPrototypeOf()或者instanceOf()方法檢測
類屬性
物件的類屬性是一個字串,用以表示物件的型別資訊.
通過內建建構函式建立的物件包含類屬性(class attribute),它與建構函式名稱相匹配,通過物件直接量和Object.create()傳教的物件的類屬性是object,自定義建構函式建立的物件類屬性也是object
可拓展性
物件的可拓展性用以表示是否可以給物件新增新屬性.所有內建物件和自定義物件都是顯式可拓展的,宿主物件的可拓展性由JavaScript引擎定義.
通過將物件傳入Object.esExtensible()來判斷物件是否可拓展,如果想將物件轉換成不可拓展,需要呼叫Object.preventExtensions()
Object.seal()將物件設定為不可拓展並且把所有自有屬性設定為不可配置,可用Object.isSealed()來檢測物件是否封閉
Object.freeze()將物件凍結,除了設定不可拓展和屬性設定不可配置外,還將自有的所有資料屬性設定為只讀,使用Object.isFrozen()判斷是否凍結
序列化物件
物件序列化是指將物件的狀態轉換成字串,也可將字串還原為物件
可以使用JSON.stringfy()和JSON.parse()來序列化和還原物件.
o = {x:1,y:{z:[false,null,""]}};
s = JSON.stringify(o);//轉換成字串 '{"x":1,"y":{"z":[false,null,""]}}'
p = JSON.parse(s);//p是o的深拷貝
JSON(JavaScript object notation)JavaScript物件表示法,JSON的語法是JavaScript語法的子集,支援物件,陣列,字串,無窮大數字,布林值和null,並且可以序列化和還原,NaN,infinity的序列化結果是null,日期物件序列化是ISO格式的日期字串,但JSON.parse()並不會還原成原始日期物件,函式,RegExp,Error物件和undefined值不能序列化和還原
物件方法
-
toString()
該方法沒有引數,它返回一個表示呼叫這個方法的物件值的字串.在需要變成字串的時候,JavaScript會呼叫這個方法,比如+
-
toLocaleString()
除了基本的toString()外,物件都包含toLocaleString()方法,這個方法返回一個表示這個物件的本地化字串,object中預設的toLocaleString()不返回任何本地化自身的操作,僅呼叫自身的toString(),Date和Number類對toLocalString()方法做了定製,可以用它對數字,日期和時間進行本地化轉換.陣列呼叫則會讓每個陣列元素呼叫toLocalString()方法轉換成字串
- toJSON()
對於需要執行序列化的物件來說,JSON.stringify()方法會呼叫toJSON()方法.
- valueOf()
該方法和toString()方法很像,但往往當JavaScript需要將物件轉換為某種原始值而非字串才會呼叫它,尤其是轉換為數字,如果在需要使用原始值的上下文中使用了物件,JavaScript就會自動呼叫這個方法