【基礎系列】javascript中的對象

此次咱們好好聊一聊對象這個東西,本次說的不是 array,也不是 function,而是 object

基礎概念

對象是一種特殊的數據類型,這種數據類型還有其餘的不少叫法,好比「散列」,「散列表」,「字典」,「關聯數組」。javascript

對象按照建立者的角度,能夠分爲三類:
內置對象:是由javascript語言自己自定義的對象,大多數是一些預約好的構造函數類,好比ArrayDateFunction
宿主對象:是指javascript解釋器所嵌入的宿主環境定義的對象,好比HTMLElement就是宿主對象。
自定義對象:是指由開發者在代碼中所建立的對象。java

咱們知道對象的表達方式是:'屬性':'值'api

屬性按照來源不一樣,能夠分爲兩類:
自有屬性:是指直接在對象中定義的屬性。
繼承屬性:是指在對象原型鏈中的屬性。數組

與此同時,對象的屬性還具備一些特性:
可寫:表明是否能夠設置該對象所對應的該屬性的值。
可枚舉:表明是否能夠經過api枚舉出該屬性。
可配置:表明是否能夠刪除或修改該屬性。函數

記住上述概念,有助於咱們進行下一步的理解。this

建立對象

建立對象有三種方式:
第一種:對象直接量spa

var o = {}
var obj = {
    a: 1,
    'b': 2,
    'min title': 3
}

第二種:經過new建立對象code

var o = new Object()

第三種:Object.create()
該方法支持傳入兩個參數,第一個參數是對象的原型(就是所建立出的對象的_proto_的指向),第二個參數是對屬性進一步的描述(該參數可選,參數內容會在後面詳解對象

clipboard.png

如下三種方式是等價的:
clipboard.pngblog

檢測對象原型的方法除了instanceof以外,還有一個isPrototypeOf(),咱們來看一下使用:

clipboard.png

對象的getter和setter

咱們首先再明確一個概念:
咱們常見的{a: 1}中的a叫作數據屬性,除此以外還有一個叫作存取器屬性,存取器屬性的值的讀取和設置,都是由getter和setter控制的。

var o = {
    p: 0,
    set q(value) {
        this.p = value
    },
    get q() {
        return this.p+=100
    }
}
o.q = 1
console.log(o.q)    // => 101
console.log(o.q)    // => 201

其中,對象中的函數定義沒有使用function關鍵字,使用的而是getset關鍵字

處理能夠這樣定義存取器屬性,咱們還能夠利用其餘的方法定義存取器屬性,就是咱們熟知的Object.defineProperty()Object.definePeoperties()

首先,咱們介紹一下Object.defineProperty()定義數據屬性的方式

var o = {}
// 定義屬性
Object.defineProperty(
    o, 
    'x', 
    {
        value: 1,
        writable: true,
        enumerable: true,
        configurable: true
    }
)
// 修改屬性
Object.defineProperty(
    o, 
    'x', 
    {
        value: 2,
        writable: false
    }
)

這個函數共有三個參數:
第一個參數是,須要加屬性的對象。

第二個參數是,添加的屬性的名稱。

第三個參數是定義的配置項:
第一個配置就是這個屬性所對應的值。
剩餘三個配置就是對應到文章一開始所提到屬性三個特性可寫可枚舉可配置
這四個配置項都不是必須填寫。假如對於新建立的屬性,value不填,默認值就是undefined,其餘配置項的缺省值是false。假如對於修改已有的屬性來講,不填寫的配置項就不作修改。

咱們再看一下Object.defineProperty()定義存取器屬性的方式
其中,須要注意的是,在定義存取器屬性時沒法定義,valuewritable配置項,由於定義的getset從某種意義上代替了前兩個配置項。

var o = {y: 1}
Object.defineProperty(
    o, 
    'x', 
    {
        set(value) {
            this.y = value
        },
        get() {
            return this.y+=100
        },
        enumerable: true,
        configurable: true
    }
)

Object.defineProperty只能單個定義或修改對象屬性,Object.defineProperties提供了批量解決的辦法,以下:

var o = {}
Object.defineProperties(
    o,  
    {
        x: {
            set(value) {
                this.y = value
            },
            get() {
                return this.y+=100
            },
            enumerable: true,
            configurable: true
        },
        y: {
            value: 1,
            writable: false,
            enumerable: true,
            configurable: true
        }
    }
)

Object.definePropertyObject.defineProperties對於屬性的修改是有規則和要求的,以下:

  1. 若是對象是不可擴展的,則能夠編輯已有的自有屬性,但不能給它添加新屬性。
  2. 若是屬性是不可配置的,則不能修改它的可配置性和可枚舉性。
  3. 若是存取器屬性是不可配置的,則不能修改其getter和setter方法,也不能將它轉換爲數據屬性。
  4. 若是數據屬性是不可配置的,則不能將它轉換爲存取器屬性。
  5. 若是數據屬性是不可配置的,則不能將它的可寫性從false修改成true,但能夠從true修改成false。
  6. 若是數據屬性是不可配置且不可寫的,則不能修改它的值。然而可配置但不可寫屬性的值是能夠修改的(其實是先將它標記爲可寫的,而後修改它的值,最後轉換爲不可寫的)。

在這裏,咱們再看一下上面的Object.create方法,Object.create的第二個參數是和Object.defineProperties第二個參數同樣的,缺省值一樣爲undefinedfalse

沒有提供選項去配置屬性特性的方法,這些屬性默認都是true,例如:new關鍵字和對象直接量的方式建立對象,以及最上面對象直接量的方式設置getter和setter

對象的擴展性

對象的擴展性是什麼,其實就是指對象可否添加新的屬性,默認狀況下全部的內置對象和自定義對象都是可擴展的。除非咱們人爲的改變它:

Object.preventExtesions()能夠傳入一個參數,就是你要取消擴展功能的對象,操做後,這個對象會不能擴展(即不能添加新屬性),且不能恢復,操做隻影響該對象自己,不對其餘原型鏈操做產生影響。
咱們能夠利用Object.esExtensible()判斷這個對象是否可擴展,傳入一個對象,返回布爾值。

Object.seal()能夠將對象封閉,效果和上面的Object.preventExtesions()同樣,增長的效果是將這個對象的自有屬性設置爲不可配置(即將configurable設爲false),一樣不能解封。
咱們能夠利用Object.isSealed()來判斷這個對象是否封閉,傳入一個對象,返回布爾值。

Object.freeze()能夠將對象冰凍,效果和上面的Object.seal()同樣,增長的效果是將這個對象的自有屬性設置爲不可寫(即將writable設爲false),一樣不能解凍。
Object.isFrozen()能夠判斷這個對象是否冰凍。

根據屬性查詢值

根據屬性查詢值的方式咱們固然是衆所周知了,[].,固然他們也能夠設置和修改可寫性爲true的自有屬性值

var o = {}
Object.defineProperties(
    o,  
    {
        x: {
            value: 1,
            writable: true,
            enumerable: true,
            configurable: true
        },
        y: {
            value: 1,
            writable: false,
            enumerable: true,
            configurable: true
        }
    }
)

o.x    // => 1
o['x'] = 5
o.x    // => 5
o.y = 5
o.y    // => 1

刪除屬性

delete能夠用戶刪除對象屬性,能刪除的屬性只是該對象的自有屬性屬性配置性爲true的屬性

讓人感到意外的是,delete只是斷開屬性和宿主對象的聯繫,而不會去操做屬性中的屬性。

clipboard.png

檢測屬性是否存在

檢測屬性共有三種方式,in操做符,hasOwnPropertypropertyIsEnumerable

in能夠檢測對象的自有屬性繼承屬性,不受屬性特性的影響

var o = {x: 1}
'x' in o    // true
'y' in o    // false
'toString' in o    // true

hasOwnProperty只能檢測對象的自有屬性,不能檢測繼承屬性,不受屬性特性的影響

var o = {x: 1}
o.hasOwnProperty('x')    // true
o.hasOwnProperty('y')    // false
o.hasOwnProperty('toString')    // false

propertyIsEnumerable只能檢測自有屬性,且要求這個屬性的可枚舉性爲true

枚舉所有屬性

首先第一個方法是for/in,這個方法能夠枚舉出當前對象可枚舉(屬性枚舉性爲true)的自有屬性和繼承屬性

var o = Object.create({z: 1})

Object.defineProperties(
    o,  
    {
        x: {
            value: 1,
            writable: true,
            enumerable: true,
            configurable: true
        },
        y: {
            value: 1,
            writable: false,
            enumerable: false,
            configurable: true
        }
    }
)

for (p in o) {console.log(p)}    // => x, z

第二個方法是Object.keys(),這個方法能夠枚舉出當前對象的可枚舉(屬性枚舉性爲true)的自有屬性,返回值是一個數組

var o = Object.create({z: 1})

Object.defineProperties(
    o,  
    {
        x: {
            value: 1,
            writable: true,
            enumerable: true,
            configurable: true
        },
        y: {
            value: 1,
            writable: false,
            enumerable: false,
            configurable: true
        }
    }
)

Object.keys(o)    // => ['x']

第三個方法是Object.getOwnPropertyNames,它能夠枚舉出當前對象全部的自有屬性(不受枚舉性影響)

Object.defineProperties(
    o,  
    {
        x: {
            value: 1,
            writable: true,
            enumerable: true,
            configurable: true
        },
        y: {
            value: 1,
            writable: false,
            enumerable: false,
            configurable: true
        }
    }
)

Object.getOwnPropertyNames(o)    // => ['x', 'y']

對象的序列化和反序列化

JSON.stringify()JSON.parse()

相關文章
相關標籤/搜索