JavaScript系列之對象

1.建立對象
(1)對象直接量,每次計算對象直接量的時候,也都會計算它的每一個屬性的值。
(2)經過new建立對象,new運算符建立並初始化一個新對象。JavaScript語言核心中原始類型都包含內置構造函數。javascript

每個JavaScript對象(null除外)都和另外一個對象相關聯。每個對象都從原型繼承屬性。
多用經過對象直接量建立的對象都具備同一個原型對象,並能夠經過JavaScript代碼Object.prototype得到對原型對象的引用。
沒有原型的對象爲數很少,Object.prototype就是其中之一。它不繼承任何屬性,其餘原型對象都是普通對象,普通對象都具備原型。全部的內置構造函數都具備一個繼承自Object.prototype的原型。java

Object,create()第一個參數是這個對象的原型,第二個可選參數,用以對對象的屬性進行進一步描述。
能夠經過傳入參數null來建立一個沒有原型的新對象,經過這種方式建立的對象不會繼承任何東西。
若是想建立一個普通的空對象,須要傳入Object.prototype數組

function inherit(p){
    if(p==null) throw TypeError();
    if(Object,create)
    return Object,create(p);
    var t=typeof p;
    if(t!=='object' && t!=='function')throw TypeError();
    function f(){};
    f.prototype=p;
    return new f();
}

new的底層原理app

function A(x,y){this.x=x;this.y=y}
var a=new A(1,2);

var a=new Object();
a.__proto__=A.prototype;
var r=A.apply(a,arguments);
if(typeof r == 'object')return r;
return a;

2.屬性的查詢和設置
當使用方括號是,方括號內的表達式必須返回字符串。更嚴格地講,表達式必須返回字符串或返回一個能夠轉換爲字符串的值。
JavaScript對象都是關聯數組。
屬性賦值操做首先檢查原型鏈,以此判斷是否容許賦值操做。
若是容許屬性賦值操做,它也老是在原始對象上建立屬性或對已有的屬性賦值,而不會去修改原型鏈。
在JavaScript中,只有在查詢屬性是纔會體會到繼承的存在,而設置屬性則和繼承無關。函數

查詢一個不存在的屬性並不會報錯,可是,若是對象不存在,那麼試圖查詢這個不存在的對象的屬性就會報錯。null和undefined值都沒有屬性,所以查詢這些值的屬性會報錯。固然,給null和undefined設置屬性也會報類型錯誤。給其餘值設置屬性也不老是成功,有一些屬性是隻讀的,不能從新賦值,有一些對象不容許新增屬性,這些設置屬性的失敗操做不會報錯。this

在這些場景下給對象o設置屬性p會失敗:
o中的屬性p是隻讀的:不能給只讀屬性從新賦值(defineProperty()方法中有一個例外,能夠對可配置的只讀屬性從新賦值)。
o中的屬性p是繼承屬性,且它是隻讀的:不能經過同名自有屬性覆蓋只讀的繼承屬性。
o中不存在自有屬性p:o沒有使用setter方法繼承屬性p,而且o的可擴展性是false。若是o中不存在p,並且沒有setter方法可供調用,則p必定會添加至o中。但若是o不是可擴展的,那麼在o中不能定義新屬性。prototype

3.刪除屬性
delete只是斷開屬性和宿主對象的聯繫,而不會去操做屬性中的屬性。
delete運算符只能刪除自有屬性,不能刪除繼承屬性。
當delete表達式刪除成功或沒有任何反作用(好比刪除不存在的屬性)時,它返回true。若是delete後不是一個屬性訪問表達式,delete一樣返回true。
delete不能刪除那些可配置性爲false的屬性。某些內置對象的屬性是不可配置的,好比經過變量聲明和函數聲明建立的全局對象的屬性。
var x=1;//聲明一個全局變量
delete this.x;//不能刪除這個屬性code

this.x=1;//建立一個可配置的全局屬性
delete this.x;對象

4.檢測屬性
in運算符的左側是屬性名(字符串),右側是對象。若是對象的自有屬性或繼承屬性中包含這個屬性則返回true。
對象的hasOwnProperty()方法用來檢測給定的名字是不是對象的自有屬性。對於繼承屬性它將返回false。
propertyIsEnumerable()是hasOwnProperty()的加強版,只有檢測到自有屬性且這個屬性的可枚舉性爲true時它才返回true。某些內置屬性是不可枚舉的。一般又JavaScript代碼建立的屬性都是可枚舉的。
!==判斷一個屬性是不是undefined
in能夠區分不存在的屬性和存在但值爲undefined的屬性。繼承

5.枚舉屬性
for/in循環能夠在循環體中遍歷對象全部可枚舉的屬性(包括自有屬性和繼承的屬性),把屬性名稱賦值給循環變量。對象繼承的內置方法不可枚舉的,但在代碼中給對象添加的屬性都是可枚舉的。
Object.keys(),它返回一個數組,這個數組由對象中可枚舉的自有屬性的名稱組成。
Object.getOwnPropertyNames(),它返回一個數組,這個數組由對象中全部自有屬性的名稱組成。

6.屬性getter和setter
和數據屬性不一樣,存取器屬性不具備可寫性。若是屬性同時具備getter和setter方法,那麼它是一個讀/寫屬性。若是它只有getter方法,那麼它是一個只讀屬性。若是它只有setter方法,那麼它是一個只寫屬性(數據屬性中有一些例外),讀取只寫屬性老是返回undefined。
和數據屬性同樣,存取器屬性是能夠繼承的。

數據屬性的4個特性分別是它的值(value)、可寫性(writable)、可枚舉性(enumerable)和可配置性(configurable)。
存取屬性不具備值特性和可寫性,它們的可寫性是由setter方法存在與否決定的。
存取器屬性的4個特性是讀取(get)、寫入(set)、可枚舉性和可配置性。

爲了實現屬性特性的查詢和設置操做,ECMAScript5中定義了一個名爲「屬性描述符」的對象,這個對象表明那4個特性。描述符對象的屬性和它們所描述的屬性特性是同名的。
經過調用Object.getOwnPropertyDescriptor()能夠得到某個對象特定屬性的屬性描述符。該方法只能獲得自有屬性的描述符,要想得到繼承屬性的特性,須要遍歷原型鏈。獲取原型的方法是Object.getPrototypeOf()

要想設置屬性的特性,或者想讓新建屬性具備某種特性,則須要調用Object.defineProperty(),傳入要修改的對象、要建立或修改的屬性的名稱以及屬性描述符對象。
傳入Object.defineProperty()的屬性描述符沒必要包含全部4個特性。對於新建立的屬性來講,默認的特性值是false或undefined。
若是要同時修改或建立多個屬性,則須要使用Object.defineProperties()。第一個參數是要修改的對象,第二個參數是一個映射表,它包含要新建或修改的屬性的名稱,以及它們的屬性描述符。

對於那些不容許建立或修改的屬性來講,若是用Object.defineProperties()和Object.defineProperty()對其操做(新建或修改)就會拋出類型錯誤異常。
若是對象是不可擴展的,則能夠編輯已有的自身屬性,但不能給它添加新屬性。
若是屬性是不可配置的,則不能修改它的可配置性和可枚舉性。
若是存取器屬性是不可配置的,則不能修改器getter和setter方法,也不能將它轉換爲數據屬性。
若是數據屬性是不可配置的,則不能將它轉換爲存取器屬性。
若是數據屬性是不可配置的,則不能將它的可寫性從false修改成true,但能夠從true修改成false。
若是數據屬性是不可配置且不可寫的,則不能修改它的值。然而可配置但不可寫屬性的值是能夠修改的。

7.對象的三個屬性
對象的原型屬性是用來繼承屬性的。
要檢測一個對象是不是另外一個對象的原型(或處於原型鏈中),請使用isPrototypeOf()方法。
在ECMAScript5中,將對象做爲參數傳入Object.getPrototypeOf()能夠查詢它的原型。

對象的類屬性

function classof(){
    if(o===null)return 'Null';
    if(o===undefined)return 'Undefined'
    return Object.prototype.toString.call(o).slice(8,-1)
}

可擴展性
全部內置對象和自定義對象都是顯式可擴展的,宿主對象的可擴展性是由JavaScript引擎定義的。
ECMAScript5定義了用來查詢和設置對象可擴展性的函數。經過將對象傳入Object.isExtensible(),來判斷對象是否可擴展的。若是想將對象轉換爲不可擴展的,須要調用Object.preventExtensions(),將待轉換的對象做爲參數傳進去。
一旦將對象轉換爲不可擴展的,就沒法再將其轉回回可擴展的了。preventExtensions()隻影響到對象自己的可擴展性。若是給一個不可擴展的對象的原型添加屬性,這個不可擴展的對象一樣會繼承這些新屬性。

可擴展屬性的目的是將對象「鎖定」,以免外界的干擾。

Object.seal()可以將對象設置爲不可擴展的,還能夠將對象的全部屬性都設置爲不可配置的。對於已經封閉起來的對象是不可解封的,可使用Object.isSealed()來檢測對象是否封閉。
Object.freeze()可以將對象設置爲不可擴展的,還能夠將對象的全部屬性都設置爲不可配置的,同時將它自有的全部數據屬性設置爲只讀。(若是對象的存取器屬性具備setter方法,存取器屬性將不受影響,仍能夠經過給屬性賦值調用它們)。使用Object.isFrozen()來檢測對象是否凍結。

8.JSON語法是JavaScript語法的子集,它並不能表示JavaScript裏的全部值。
支持對象、數組、字符串、無窮大數字、true、false和null,而且它們能夠序列化和還原。NaN、Infinity和-Infinity序列化的結果是null,日期對象序列化的結果是ISO格式的日期字符串。函數、RegExp、Error對象和undefined值不能序列化和還原。JSON.stringify()只能序列化對象可枚舉的自有屬性。對於一個不能序列化的屬性來講,在序列化後的輸出字符串中會將這個屬性省略掉。

JSON的全稱是javascript Object Notation,JavaScript對象表示法。

相關文章
相關標籤/搜索