javascript對象
動態:可新增、刪除屬性;
但常來模擬靜態對象以及靜態類型語言中的結構體(struct),有時也做字符串的集合。
除了字符串、數字、true、false、null、undefined之外,其他的javascript都是對象。儘管字符串、數字、布爾值不是對象,行爲和不可變對象相似。
方法:
create、set、query、delete、test、enumerate
屬性特徵:
1.可寫:表明是否可設置改屬性的值
2.可枚舉:表明是否可以通過for/in循環返回該屬性
3.可配置:表明是否可以刪除或修改該屬性
注:ECMAScript5之前,代碼給對象創建的所有屬性都是可枚舉的。之後有改變
對象特性:
1.對象的原型(protype)指向另一個對象,本對象的屬性繼承與它的原型對象
2.對象的類(class)是一個表示對象類型的字符串
3.對象的擴展標記(exensible flag)指明瞭是否可以向該對象添加新屬性
三類對象和兩類屬性:
1.內置對象(native object):ECMAScript規範定義的對象或類。例如:數組、函數、日期、正則表達式
2.宿主對象(host object):javascript解釋器鎖嵌入的宿主環境,例如:web瀏覽器定義的。網頁結果中的htmlelement都是宿主對象。宿主環境定義的方法都可以看做普通javascript的函數對象,那麼宿主對象也可以當做內置對象
3.自定義對象(user-defind object):由運行的javascript代碼創建的對象
4.自有屬性(own property):直接在對象中定義的屬性
5.繼承屬性(inherited property):在對象的原型對象中定義的屬性
原型:
所有通過對象直接量創建的對象都具有同一個原型對象,並可以通過JavaScript代碼Object.prototype獲得對原型對象的引用。
new Object() ---> Object.prototype
new Array() ---> Array.prototype
Object.create()
靜態函數,不提供給某個對象調用,只需傳入所需原型對象即可
var test = Object.create(Object.prototype); //和{}、new Object()一樣
//通過運行繼承創建一個新對象
function inherit(p) {
if(p == null) throw TypeError(); //p是一個對象不能爲Null
if(Object.create) return Object.create(p); //如果Object.create存在,則直接使用
var t = typeof p;
if(t != 'object' && t != 'function') throw TypeError(); //進一步檢測
function f(){} //空構造函數
f.prototype = p; //將其原型屬性設置爲p
return new f(); //使用f()創建p的繼承對象
}
屬性訪問錯誤
如果對象不存在,則試圖查詢對象的屬性就會報錯。 null和undefined值都沒有屬性
//一種冗餘但很易懂的方法
var len = undefined;
if(book) {
if(book.subtitle) len=book.subtitle.length;
}
//簡練語法
var len = book && book.subtitle && book.subtitle.length;
刪除屬性
delete運算符可以刪除對象的屬性。它的操作數應當是一個屬性訪問表達式。 但是,delete只是斷開屬性和宿主對象的聯繫,而不會操作屬性中的屬性
delete運算符只能刪除自有屬性,不能刪除繼承屬性(要刪除繼承屬性,必須從定義這個屬性的原型對象刪除它,而且會影響到所有繼承自這個原型的對象)
檢測屬性
判斷某個屬性是否存在於某個對象中,可以通過in運算符、hasOwnPreperty()和propertyIsEnumerable()方法等。
對象的hasOwnProperty()方法:檢測給定的名字是否是對象的自有屬性,對於繼承屬性返回false
propertyIsEnumerable():只有檢測到是自有屬性且這個屬性的可枚舉性爲true是才返回true
in運算符
!==:判斷一個屬性是否是undefined
var o = {x:0}
o.x !== undefined; //true
o.y !== undefined; //false
o.toString !== undefined; //true
有一種場景只能使用in運算符,而不能使用上述屬性訪問的方式。 in可以區分不存在的屬性和存在但值爲undefined的屬性
var o = {x:undefined};
o.x !== undefined; //false:屬性存在,值爲undefined 此時會有問題
o.y !== undefined;
'x' in o; //true:屬性存在
'y' in o; //false
delete o.x; //刪除x
‘x’ in o; //false
//把p中可枚舉的屬性賦值到o中,並返回o。 如果有同名屬性,則覆蓋
function extend(o,p) {
for(prop in p) {
o[prop] = p[prop];
}
return o;
}
//將p中可枚舉的屬性複製到o中,並返回o。 如果o和p中有同名屬性,o中不受影響
function merge(o,p) {
for(prop in p) {
in(o.hasOwnProperty[prop]) continue;
o[prop] = p[prop];
}
return o;
}
//如果o中的屬性再p中沒有同名屬性,則從o中刪除這個屬性
function restrict(o,p) {
for(prop in o) {
if(! (prop in p)) delete o[prop];
}
return o;
}
//如果o中的屬性在p中存在同名屬性,則從o中刪除這個屬性
function subtract(o, p) {
for(prop in p) {
delete o[prop];
}
return o;
}
//返回一個新對象,這個對象同時擁有o的屬性和p的屬性; 如果有重名,則使用p中屬性
funciton union(o, p) {
return extend(extend({}, o), p);
}
//返回一個新對象,同時擁有o和p的屬性,像求交集。p中屬性的值被忽略
function intersection(o,p) {
return restrict(extend({}, o), p);
}
屬性的特性
- 值(value)
- 可寫性(writable)
- 可枚舉性(enumerable)
- 可配置性(configurable)
通過調用Object.getOwnPropertyDescriptor()可以獲得某個對象特定屬性的屬性描述符
//得到自有屬性的描述符
Object.getOwnPropertyDescriptor({x:1}, 'x');
//獲得繼承屬性的特性,需要遍歷原型鏈
Object。getPrototypeOf();
//要想設置屬性的特性,或者讓新建屬性具有某種特性。
Object.definePeoperty(); //傳入要修改的對象,要創建或修改的屬性的名稱以及屬性描述符對象
var o = {};
//創建一個不可枚舉的數據屬性x,賦值爲1
Object.defineProperty(o, 'x', {
value : 1,
writable:true,
enumerable:false,
configurable:true
});
//屬性存在不可枚舉
o.x; // 1
Object.keys(o) //[]
//對屬性x進行修改,變爲只讀
Object.defineProperty(o, 'x', {writable:false});
//試圖更改這個屬性的值
o.x = 2//操作失敗但報錯,在嚴格模式裏面會拋出類型錯誤異常
o.x == 1 //true
//配置屬性
Object.defineProperty(o, 'x',{value:2});
//強x從數據屬性修改爲存取器屬性
Object.defineProperty(o, 'x', {get:function(){return 0;}});
Object.defineProperty()的屬性描述符對象不必包含所有4個特性。
對於新建屬性:默認特性值是false或undefined。
對於修改已有屬性:默認的特性值沒有做任何修改
如果同時修改多個屬性,則使用Object.defineProperties();
參數:
1. 要修改的對象
2. 映射表,包含要新建或修改的屬性的名稱,以及他們的屬性描述符
var p = Object.defineProperties({}, {
x:{value:1, writable:true, enumerable:true, configurable:true},
y:{value:1, writable:true, enumerable:true, configurable:true},
r:{
get:function() {return Math.sqrt(this.x*this.x + this.y*this.y)},
enumerable:true,
configurable:true
}
});
原型屬性、類屬性、可擴展性、序列化對象
原型屬性
//ECMAScript5:傳遞對象,可獲取對象的原型
Object.getPrototypeOf()
//ECMAScript3
o.constructor.prototype檢測一個對象的原型
類屬性
function classof(o) {
if(o === null) return 'Null';
if(o === undefined) return 'Undefined';
return Object.prototype.toString.call(o).slice(8, -1);
}
解析:
1. object.prototype:object的原型對象,代表繼承關係
2. toString:方法名
3. call(o):返回數據的類型
4. 獲取裏面的值,兩個參數截取:包前不包後,負數依然是包前不包後,但是是代表從結尾計數的。
//demo
var p = {x:1};
var o = Object.create(p);
p.isPrototypeOf(o) //true:o繼承與p
Object.prototype.isPrototype(o) //true,p繼承與Object.prototype
可擴展性
Object.esExtensible(); //判斷該對象是否可擴展
Object.preventExtensions(); //對象會變成不可擴展的。 改方法只會影響對象本身的可擴展性。如果給一個不可擴展的對象的原型添加屬性,這個不可擴展的對象同樣會繼承這些新屬性
Object.seal()
序列化對象
指:將對象的狀態轉換爲字符串,也可以將字符串還原爲對象
JSON.stringify() //序列化
JSON.parse() //還原對象
注意:
1. 支持對象、數組、字符串、無窮大數字、true、false和null
2. NaN、Infinity和-Infinity序列化結果依然是null
3. 日期對象序列化的結果是:ISO格式的日期字符串,但JSON.parse()依然保留他們的字符串形態,而不會還原成日期對象
4. 函數、RegExp、Error對象不支持
5. JSON.stringify() 只能序列化對象可枚舉的自有屬性,對於一個不能序列化的屬性來說,在序列化後的輸出字符串會忽略該屬性