深入理解js對象

定義對象

兩種方式定義對象

let person = new Object()
obj.name = '蛙人'
obj.age = 23
obj.sex = 'male'
obj.getAge = function() {
    return this.age
}

上面的例子創(chuàng)建了一個person對象實例,并為它添加了屬性及方法,在早期js開發(fā)人員經常使用這種方式,但是現(xiàn)在對象字面量成了首先方式,看一下字面量定義對象。

let person = {
    name: '蛙人',
    age: 23,
    sex: 'male',
    getAge() {
        return this.age
    }
}

可以看到上面這種使用字面量的方式定義對象更加簡潔明了,字面量的方式跟第一種定義方式是一樣的。

屬性類型

在說數據屬性時,咱們先來講一下js里的內部屬性, 在Es5版本中,在定義只有內部才用的特性attribute時,描述了屬性property的各種
特征, 定義這些特性是為了實現(xiàn)js引擎用的,因此在js里無法訪問內部屬性,內部屬性是兩個中括號括起來的例如 [[Enumerable]]

數據屬性

數據屬性包含一個數據值的位置,在這個位置可以進行讀取和寫入值,那么這就是數據屬性描述對象。

  • [[Configuralbe]] : 表示是否可以delete刪除該屬性,是否能在對象上定義其它屬性,是否能修改屬性值,默認返回true。
  • [[Enumerable]] :表示是否可以枚舉該屬性for in, 默認返回true。
  • [[Writeable]] : 表示是否可以讀寫改屬性,默認返回true。
  • [[Value]] : 表示屬性值的位置,每次讀取屬性的時,從這個[[Value]]內部屬性返回值,寫入屬性值的時候,把值保存在這個位置,默認返回undefined,這也就是我們所讀取對象上不存在的屬性時,返回undefined的原因。

理論講完了,那么直接上代碼一把梭


[[Value]]

let person = {
    name: '蛙人'
}

上面example中定義屬性name,為它的值默認 “蛙人” 也就是說,在內部屬性 [[Value]] 中保存了該值, 從這點我們明白,只要是對象中修改或寫入值,都會觸發(fā)內部屬性 [[Value]]

修改屬性描述對象

如果要修改數據屬性的描述對象,使用Es5中Object.defineProperty()方法,這個方法接收三個參數,目標對象、要訪問的屬性、屬性的描述對象,描述對象必須是: configurable、enumerable,writeable、value, 設置其中一或多屬性,可以修改對應的描述屬性值。

let person = {}
Object.defineProperty(person, 'name', {
    writeable: false, // 不能寫入
        value: '你沒有permission'
})

console.log(person.name) // 你沒有permission
person.name = "蛙人"
console.log(person.name) // 你沒有permission

在上面example中,我們設置了person對象描述對象為只讀不可寫,又為它設置了value屬性,所以不管它怎么讀取都返回你沒有permission,怎么寫都不可以,需要注意的是上面代碼在嚴格模式下會拋出錯誤,在非嚴格模式下賦值操作則會忽略, 而且更為重要的一點,Object.defineProperty第三個參數必須寫,不然code報錯

訪問器屬性

數據訪問器屬性不包含數據值, 他們包含一對 getter和setter函數 (這兩個函數不是必需的 可選)。

在讀取訪問器屬性時,會調用getter函數,在寫入訪問器屬性時,會調用setter函數,函數接收一個參數這個參數就是寫入的值。

  • [[get]]:在讀取屬性時調用的函數,默認返回undefined
  • [[set]]:在寫入屬性時調用的函數,默認返回undefined
    訪問器屬性不能直接定義,使用Object.defineProperty(),請看下面 example
let person = {
    _age: 23,
    name: '蛙人'
}

Object.defineProperty(person, "age", {
    get() {
        return this._age
    },
    set(val) {
        this._age = val
    }
})
person.age = 24

上面example中,寫入age屬性就會觸發(fā)訪問器對象里的set函數,從而重新賦值,然后觸發(fā)get方法,返回該屬性值,上面使用了_age這種定義方式表示為常用的mark,表示只能通過對象方法訪問的屬性, 不要直接寫在get函數返回里返回自身 如:this.age = xxx 這樣會造成堆棧溢出

定義多個描述屬性

Es5版本中還有一個Api方法是定義多個對象寫入描述屬性, 該方法接收2個參數,目標對象、屬性值,請看下列example

let person = {}
Object.defineProperties(person, {
    _age: {
        value: 23
    },
    name: {
        value: "蛙人"
    },
    age:{
        get() {
            return this._age
        },
        set(val) {
            this._age = val;
        }
    }
})

上面example與 上一個example都是同樣的代碼效果,只不過定義方式不同,該方法不經常使用,大家知道就好。

獲取對象的描述屬性

Es5版本中定義了一個Api方法可以查看當前對象的描述屬性,Object.getOwnPropertyDescriptor(), 該方法接收2個參數,目標對象、屬性值。

let person = {
     age: 23
}
let descriptor = Object.getOwnPropertyDescriptor(person, "age")
console.log(descriptor.writable)  // true
console.log(descriptor) // {"value":23,"writable":true,"enumerable":true,"configurable":true}

上面example中可以清楚的看見當前的對象屬性的描述對象,這樣在出現(xiàn)bug的時候,我們也可以查看當前的描述屬性是否可以更改,快速定位bug,在js中可以針對任何對象使用Object.getOwnPropertyDescriptor(), 包括BOM和DOM對象,兼容IE9 +、Firefox4+、Safari5+、Opera12+、Chrome。


<b>如果該文章對你有幫助,請點個贊吧</b>

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容