1. 程式人生 > >【JS】《你不知道的JavaScript》 之 物件

【JS】《你不知道的JavaScript》 之 物件

簡單基本型別(string、boolean、number、null、undefined)本身並不是物件,但是typeof null時會返回字串‘object’。但實際上,null本身是基本型別。

原理是這樣的。不同的物件在底層都表示二進位制,在js中二進位制前三位都為0的話會被判斷為object,null的二進位制表示全部為0,自然前三位也是0.所以執行typeof時會返回‘object’。

陣列

陣列也是物件,所以雖然每個下標都是整數,仍可以給陣列新增屬性

var myArr = ['foo', 42, 'bar']
myArr.baz = 'baz'
myArr.length     // 3
myArr.baz        // 'baz'

雖然添加了命名屬性,陣列的length值並未發生變化。

如果試圖向陣列新增一個屬性,但是屬性名‘看起來’像一個數字,那它會變成一個數值下標(因此會修改陣列的內容而不是新增一個屬性)

var myArr = ['foo', 42, 'bar']
myArr['3'] = 'baz'
myArr.length   // 4
myArr[3]       // 'baz'

屬性描述符

var myObj = {a:2}
Object.getOwnPropertyDescriptor(myObj, 'a')
// {value: 2, writable: true, enumerable: true, configurable: true}

這個普通的物件屬性對應的屬性描述符不僅僅是一個2.它還包含另外三個特性:writable、enumerable和configurable。

在建立普通屬性時屬性描述符會使用預設值,可以使用Object.defineProperty()來新增一個新屬性或者修改一個已有屬性(如果是configurable)。

var myObj = {}
Object.defineProperty(myObj, 'a', {
    value: 3,
    configurable: true,
    enumerable: true,
    writable: true
})
myObj.a   // 2

除了defineProperty外還有defineProperties方法,差別如下:

Object.defineProperty(obj, prop, descriptor)
Object.defineProperties(obj, props)
  • writable決定是否可以修改屬性的值
  • configurable決定屬性是否可配置,只要屬性是可配置的,就可以使用defineProperty()方法來修改屬性描述符(把configurable修改為false是單向操作,無法撤銷);configurable: false 還會禁止刪除這個屬性
  • enumerable決定的是該屬性是否會出現在物件的屬性列舉中。

不變性

  1. writable: false 和 configurable: false 就可以建立一個真正的常量屬性。
  2. 若想禁止一個物件新增新屬性並且保留已有屬性,可以使用Object.preventExtensions()。
  3. Object.seal()會建立一個‘密封’的物件,這個方法實際上會在一個現有物件上呼叫Object.preventExtensions()並把所有現有屬性標記為configurable: false。
  4. Object.freeze()會建立一個凍結物件,這個方法實際上會在一個現有物件上呼叫Object.seal()並把所有‘資料訪問’屬性標記為writable: false。

存在性

  • in 會檢查物件及其原型鏈
  • hasOwnProperty 只會檢查物件
  • propertyIsEnumerable會檢查物件 並且 滿足enumerable: true
  • Object.keys()會返回一個數組,包含所有可列舉屬性
  • Object.getOwnPropertyNames()會返回一個數組,包含所有屬性,無論他們是否可列舉