開場白
很抱歉,開始講述知識點之前還是要讓你看一段不那么重要的開場白忆首。
今天去了自己最為向往的公司參加了第二輪面試柱搜,跟CEO聊天的感覺真的非常好夫凸,希望自己能進去吧。但是不管怎么說,日子總得要過吧蒜绽。如果真的不幸沒有辦法進入該公司,或許我能做的也就是整理著裝,重新踏上求職之旅吧。不過在這之前楣导,還是要每天學點javascript
吧?
今天主要講述下面這兩組方法
1. Object.keys
與Object.getOwnPropertyNames
的異同片仿。
2. Object.seal
, Object.preventExtensions
以及Object.freeze
可以在不同程度增強對象的健壯性。
正文
1. Object.keys
跟 Object.getOwnPropertyNames
的異同
兩個方法都是可以用來獲取指定對象的自有屬性的尤辱。那么它們有什么不同呢砂豌?
之前已經稍微提及過Object.keys
了,它是用來獲取一個對象的自有屬性光督。比如:
> var a = {x: 1, y: 2}
undefined
> a
{ x: 1, y: 2 }
> Object.keys(a)
[ 'x', 'y' ]
那它有什么局限呢阳距?更確切地說它只能用來獲取對象可枚舉的自有屬性,我們看看下面的例子结借。
> Object.getOwnPropertyDescriptor(a, 'x')
{ value: 1, writable: true, enumerable: true, configurable: true }
> Object.defineProperty(a, 'x', {enumerable: false}) // 設置x屬性為不可枚舉的
{ y: 2 }
> a
{ y: 2 }
> Object.keys(a)
[ 'y' ]
可見筐摘,現在我們只能獲取到對象a
的自有的并且是可枚舉的屬性。如何獲得對象a
的自有屬性船老,并且不管它們是否是可枚舉的呢咖熟?這個時候我們可以考慮用Object.getOwnPropertyNames
。
> Object.getOwnPropertyNames(a)
[ 'x', 'y' ]
這樣就可以獲取對象a
的所有自有的屬性努隙,包括了不可枚舉的屬性球恤。如果我們需要遍歷對象a
的所有自有屬性辜昵,這個方法就能派上用場了荸镊。
2. Object.seal
, Object.preventExtensions
以及Object.freeze
可以在不同程度增強對象的健壯性。
這里就有一個問題,什么是對象的可擴展性?我用比較直白的話說就是“是否能夠為這個對象添加屬性?”躬存。我們可以用Object.isExtensible
來判斷對象是否是可以擴展的。
> Object.isExtensible(1)
false
> Object.isExtensible({})
true
> Object.isExtensible("lanzhiheng")
false
字符串不可以擴展?你在逗我嗎幽崩?
對的呼盆,我們這里用的是字符串的字面量,它是不可以擴展的盾剩。做個實驗:
> var str = "lanzhiheng"
undefined
> str.age = 12
12
> str.age
undefined
我們試圖給str添加一個屬性雷激,然而最后查找的時候并沒有設置成功,原因是
當我們添加屬性的時候告私,JS會臨時創(chuàng)建一個字符串的對象屎暇,并且它包裝了原來的字符串字面量,所以這里并不會報錯驻粟。但是當我們執(zhí)行完
str.age = 12
之后這個對象自動銷毀了根悼,所以這個屬性添加是沒有作用的。
好啦蜀撑,回到正題挤巡,下面是ES5之后才有的靜態(tài)方法。我們按順序來說說酷麦。
1. Object.preventExtensions
讓對象變成不可擴展的
來看例子:
> var b = {x: 1, y: 2}
undefined
> b.z = 13
13
> Object.preventExtensions(b) // 保護可擴展性
{ x: 1, y: 2, z: 13 }
> b.k = 100
100
> b
{ x: 1, y: 2, z: 13 }
可見矿卑,一開始給對象b
添加屬性是可以的,然而贴铜,我們調用了Object.preventExtensions
之后這個設置就失敗了粪摘,在嚴格模式下甚至還會報錯
TypeError: Can't add property x, object is not extensible
2. Object.seal
讓對象變成不可擴展的并且把已有的屬性設置成不可配置的
這里我們簡單把不可配置理解成不可刪除
,(當然絕不是那么簡單而已)。我們來操作一下新對象c
绍坝。
> c = {x: 1, y: 2, z: 3}
{ x: 1, y: 2, z: 3 }
> c.kk = 12 // 添加屬性
12
> c
{ x: 1, y: 2, z: 3, kk: 12 }
> delete c.kk // 刪除屬性
true
> c
{ x: 1, y: 2, z: 3 }
目前為止是很正常
的徘意,現在用Object.seal
來處理一下好吧。
> Object.seal(c)
{ x: 1, y: 2, z: 3 }
> c.kk = 1000 // 添加屬性
1000
> c // 無效
{ x: 1, y: 2, z: 3 }
> delete c.x // 刪除屬性
false
> c // 無效
{ x: 1, y: 2, z: 3 }
發(fā)現處理之后對c
對象進行擴展以及刪除屬性這些操作都不生效了(嚴格模式下還會報錯)轩褐,這就是Object.seal
方法的作用椎咧。可以保護對象的屬性以及對象本身, 我們可以方便地用Object.isSealed
來判斷對象是否具有這類屬性把介。
> Object.isSealed(c)
true
同時勤讽,我們也可以用來判斷對象是否具有不可擴展且屬性不可配置
這些特征,即便它沒有經過Object.seal
處理
> var a = {x: 1, y: 2}
undefined
// 設置對象為不可擴展的
> Object.preventExtensions(a)
{ x: 1, y: 2 }
> Object.isSealed(a)
false
// 設置對應的屬性的特性為不可配置的
> Object.defineProperties(a, {x: {configurable: false}, y: {configurable: false}})
{ x: 1, y: 2 }
> Object.isSealed(a)
true
這個方法是不是還不錯?另外, 雖然我們無法對對象的已有結構
進行修改拗踢,但是我們卻依然可以修改對象已有的屬性的值
> c
{ x: 1, y: 2, z: 3 }
> c.x = 100
100
> c
{ x: 100, y: 2, z: 3 }
要怎樣更進一步方便地提高健壯性脚牍,把所有屬性都弄成不可寫的,并且不可配置的呢巢墅?這個時候會用到下面要介紹的Object.freeze
方法诸狭。
3. Object.freeze 讓對象變成不可擴展的, 并且把已有的屬性設置成不可配置并且不可寫
這里不多說明券膀,直接舉例子
> var d = {x: 1, y: 2, c: 3}
undefined
> Object.freeze(d)
{ x: 1, y: 2, c: 3 }
> d.kk = 100 // 擴展對象d
100
> d
{ x: 1, y: 2, c: 3 }
> delete d.x // 刪除對象d屬性
false
> d
{ x: 1, y: 2, c: 3 }
> d.x = 100 // 修改對象d屬性的值
100
> d
{ x: 1, y: 2, c: 3 }
可見對象d
進行了上面操作依然沒有任何改變。同樣的, 我們也可以用Object.isFrozen
來判斷對象是否有對應的特性驯遇。
> Object.isFrozen(d)
true
這里就不用復雜的例子了芹彬,跟Object.isSealed
是差不多的。
當然叉庐,如果要對這些進行過保護的特性進行
非法
操作舒帮,在嚴格模式下是會拋出異常的。
> var dStrict = {x: 1, y: 2}
undefined
> Object.freeze(dStrict)
{ x: 1, y: 2 }
> dStrict.x = 100
TypeError: Cannot assign to read only property 'x' of object '#<Object>'
以上這點寫代碼的時候需要注意一下陡叠。畢竟嚴格模式跟非嚴格模式有很多行為都是有所區(qū)別的玩郊。
最后
終于到了尾聲了,今天介紹的方法稍微多了一些枉阵,不過都是相關聯(lián)并且比較方便記憶的瓦宜,希望讀者閱讀的時候不會太難受。