摘要:嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出異常嚴格模式。
擴展特性
Object.isExtensible 方法
Object.preventExtensions 方法
密封特性
Object.isSealed 方法
Object.seal 方法
凍結特性
Object.isFrozen 方法
Object.freeze 方法
淺凍結 與 深凍結
擴展特性如果一個對象可以添加新的屬性,則這個對象是可擴展的。
讓這個對象變的不可擴展,也就是不能再有新的屬性
我們都知道,我們可以通過屬性描述符創建屬性不可配置對象 如何讓對象屬性不可配置或枚舉,
在這里我們可以創建不可擴展屬性的對象
MDN:
概述 Object.isExtensible() 方法判斷一個對象是否是可擴展的(是否可以在它上面添加新的屬性)。 語法 Object.isExtensible(obj) 參數 obj 需要檢測的對象
使用:
//新對象默認是可擴展的無論何種方式創建的對象,這里使用的是字面量方式 var empty = {a:1}; console.log(Object.isExtensible(empty) === true);//true //等價于 使用屬性描述符 empty = Object.create({},{ "a":{ value : 1, configurable : true,//可配置 enumerable : true,//可枚舉 writable : true//可寫 } }); console.log(Object.isExtensible(empty) === true);//true //對象是否可以擴展與對象的屬性是否可以配置無關 empty = Object.create({},{ "a":{ value : 1, configurable : false,//不可配置 enumerable : true,//可枚舉 writable : true//可寫 } }); console.log(Object.isExtensible(empty) === true);//true
那么我們如何讓一個對象變成不可擴展:
Object.preventExtensions 方法MDN:
概述 Object.preventExtensions() 方法讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性。 語法 Object.preventExtensions(obj) 參數 obj 將要變得不可擴展的對象 描述 如果一個對象可以添加新的屬性,則這個對象是可擴展的。 preventExtensions 可以讓這個對象變的不可擴展,也就是不能再有新的屬性。 需要注意的是不可擴展的對象的屬性通常仍然可以被刪除。 嘗試給一個不可擴展對象添加新屬性的操作將會失敗,不過可能是靜默失敗,也可能會拋出 TypeError 異常(嚴格模式)。 Object.preventExtensions 只能阻止一個對象不能再添加新的自身屬性,仍然可以為該對象的原型添加屬性。
使用:
(function () { //Object.preventExtensions 將原對象變得不可擴展,并且返回原對象. var obj = {}; var obj2 = Object.preventExtensions(obj); console.log(obj === obj2);//true //新創建的對象默認是可擴展的 var empty = {}; console.log(Object.isExtensible(empty) === true);//true empty.a = 1;//添加成功 //將其變為不可擴展對象 Object.preventExtensions(empty); console.log(Object.isExtensible(empty) === false);//true //使用傳統方式為不可擴展對象添加屬性 empty.b = 2;//靜默失敗,不拋出錯誤 empty["c"] = 3;//靜默失敗,不拋出錯誤 //在嚴格模式中,為不可擴展對象添加屬性將拋出錯誤 (function fail(){ "use strict"; empty.d = "4";//throws a TypeError })(); //使用 Object.defineProperty方法為不可擴展對象添加新屬性會拋出異常 Object.defineProperty(empty,"e",{value : 5});//拋出 TypeError 異常 Object.defineProperty(empty,"a",{value : 2}); console.log(empty.a);//輸出2 })();
在上述代碼的最后兩行可以看到如果為當前不可擴展對象 empty 修改屬性是成功的,這是因為一個對象的屬性是否可以被修改與該對象是否可以擴展無關,而是與該對象在創建的時候是否聲明為不可重寫有關(Writable)
如果我們想讓一個對象的所有屬性都不可配置同時也不允許為該對象進行擴展怎么做:
(function () { //創建一個對象,同時聲明其所有屬性均為不可配置且不可寫 var obj = {a :1,b:2,c:3}; Object.defineProperties(obj,{ "a":{configurable:false}, "b":{configurable:false}, "c":{configurable:false} }); //等價于 var obj = Object.create({},{ "a":{value :1,congigurable :false,enumerable :true,writable:true}, "b":{value :2,congigurable :false,enumerable :true,writable:true}, "c":{value :3,congigurable :false,enumerable :true,writable:true} }); //將其轉化為不可擴展對象 Object.preventExtensions(obj); //測試該對象是否即不可擴展同時其所有屬性均不可配置 console.log(Object.isExtensible(obj) === true);//false for(var name of Object.keys(obj)){//遍歷該對象的所有可枚舉屬性名,不包括繼承而來的屬性 Object.defineProperty(obj,name,{enumerable:false});//將該屬性的 enumerable 特性重新配置為 true }//拋出異常 })();
雖然說上面的程序實現了需求,但未免太麻煩,這里我們可以使用 JS 對象的另一特性 密封
密封特性密封對象是指那些不可 擴展 的,且所有自身屬性都不可配置的(non-configurable)對象。
或則說 密封對象是指那些不能添加新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性,但可能可以修改已有屬性的值的對象。
Object.isSealed 方法MDN:
概述 Object.isSealed() 方法判斷一個對象是否是密封的(sealed)。 語法 Object.isSealed(obj) 參數 obj 將要檢測的對象 描述 如果這個對象是密封的,則返回 true,否則返回 false。
使用:
(function () { //新建的對象默認不是密封的 var empty = {}; console.log(Object.isSealed(empty) === false);//true //如果把一個空對象變得不可擴展,則它同時也會變成個密封對象. Object.preventExtensions(empty); console.log(Object.isSealed(empty) === true);//true //但如果這個對象不是空對象,則它不會變成密封對象,因為密封對象的所有自身屬性必須是不可配置的. var hasProp = {fee : "fie foe fum"}; Object.preventExtensions(hasProp); console.log(Object.isSealed(hasProp) === false);//true //如果把這個屬性變得不可配置,則這個對象也就成了密封對象. Object.defineProperty(hasProp,"fee",{configurable : false}); console.log(Object.isSealed(hasProp) === true);//true })();Object.seal 方法
MDN:
概述 Object.seal() 方法可以讓一個對象密封,并返回被密封后的對象。 密封對象是指那些不能添加新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性,但可能可以修改已有屬性的值的對象。 語法 Object.seal(obj) 參數 obj 將要被密封的對象 描述 通常情況下,一個對象是可擴展的(可以添加新的屬性)。 密封一個對象會讓這個對象變的不能添加新屬性,且所有已有屬性會變的不可配置。 屬性不可配置的效果就是屬性變的不可刪除,以及一個數據屬性不能被重新定義成為訪問器屬性,或者反之。 但屬性的值仍然可以修改。 嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出TypeError 異常(嚴格模式)。 不會影響從原型鏈上繼承的屬性。但 __proto__ ( ) 屬性的值也會不能修改。
使用:
(function () { var obj = { //聲明一個對象 prop:function(){}, foo:"bar" }; //可以添加新的屬性,已有屬性的值可以修改,可以刪除 obj.foo = "baz"; obj.lumpy = "woof"; delete obj.prop; var o = Object.seal(obj);//將 obj 密封,且返回原對象 console.log(o === obj);//true console.log(Object.isSealed(obj) === true);//true //仍然可以修改密封對象上的屬性的值 obj.foo = "quux";//修改成功 //但不能把密封對象的屬性進行重新配置,譬如講數據屬性重定義成訪問器屬性. //Object.defineProperty(obj,"foo",{get : function(){return "g";}});//拋出 TypeError //任何除修改屬性值以外的操作都會失敗 obj.quaxxor = "the friendly duck";//靜默失敗,屬性沒有成功添加 delete obj.foo;//靜默失敗,屬性沒有刪除成功 //在嚴格模式中,會拋出 TypeError 異常 (function fail(){ "use strict"; //delete obj.foo;//拋出 TypeError 異常 //obj.sparky = "arf";//拋出 TYpeError 異常 })(); Object.defineProperty(obj,"ohai",{value :17});//添加屬性失敗 Object.defineProperty(obj,"foo",{value : "eit"});//修改成功 console.log(obj.foo);//“eit” })();
如上面程序所示,將一個對象密封后僅能保證該對象不被擴展且屬性不可重配置,但是原屬性值卻是有可能被修改的,若要達到即密封又不可修改原屬性值可以這樣:
//創建不可修改值的密封對象 (function () { //方式一 var o = {a:1}; Object.defineProperty(o,"a",{configurable:false,writable:false}); Object.preventExtensions(o); o.a = 2; console.log(o.a);//1 console.log(Object.isExtensible(o) ===false);//true console.log(Object.isSealed(o) === true);//true //方式二 o = Object.create(Object.prototype,{"a":{value :1,writable:false}}); Object.seal(o); o.a = 2; console.log(o.a);//1 console.log(Object.isExtensible(o) ===false);//true console.log(Object.isSealed(o) === true);//true //方式... })();
同樣的,雖然實現了需求,依舊可以使用另一特性 凍結
凍結特性一個對象是凍結的(frozen)是指它不可擴展,所有屬性都是不可配置的(non-configurable),且所有數據屬性(data properties)都是不可寫的(non-writable)。
數據屬性是值那些沒有取值器(getter)或賦值器(setter)的屬性。
或則說 凍結對象是指那些不能添加新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性的對象。也就是說,這個對象永遠是不可變的。
Object.isFrozen 方法MDN:
概述 Object.isFrozen() 方法判斷一個對象是否被凍結(frozen)。 語法 Object.isFrozen(obj) 參數 obj 被檢測的對象 描述 一個對象是凍結的(frozen)是指它不可擴展,所有屬性都是不可配置的(non-configurable),且所有數據屬性(data properties)都是不可寫的(non-writable)。數據屬性是值那些沒有取值器(getter)或賦值器(setter)的屬性。
使用:
(function () { //一個對象默認是可擴展的,所以他也是非凍結的. console.log(Object.isFrozen({}) === false);//true //一個不可擴展的空對象同時也是一個凍結對象.一個不可擴展的空對象也是密封對象 var vacuouslyFrozen = Object.preventExtensions({}); console.log(Object.isFrozen(vacuouslyFrozen) === true);//true console.log(Object.isSealed(vacuouslyFrozen) === true);//true //一個非空對象默認也是非凍結的. var oneProp = { p:42 }; console.log(Object.isFrozen(oneProp) === false);//true //讓這個對象變的不可擴展,并不意味著這個對象變成了凍結對象,因為 p 屬性仍然是可以配置的(而且可寫的). Object.preventExtensions( oneProp ); console.log(Object.isFrozen(oneProp) === false);//true //如果刪除了這個屬性,則它成為空對象,會成為一個凍結對象. delete oneProp.p; console.log(Object.isFrozen(oneProp) === true); //一個不可擴展的對象,擁有一個不可寫但可配置的屬性,則它仍然是非凍結的. var nonWritable = { e : "plep" }; Object.preventExtensions(nonWritable); Object.defineProperty(nonWritable,"e",{writable : false});//不可寫 console.log(Object.isFrozen(nonWritable) === false);//true //把這個屬性改為不可配置,會讓這個對象成為凍結對象 Object.defineProperty(nonWritable,"e",{configurable : false});//不可配置 console.log(Object.isFrozen(nonWritable) === true);//true //一個不可擴展的對象,擁有一個不可配置但可寫的屬性,則它仍然是非凍結的. var nonConfigurable = { release : "the kraken!" }; Object.preventExtensions(nonConfigurable); Object.defineProperty(nonConfigurable,"release",{configurable : false}); console.log(Object.isFrozen(nonConfigurable) === false);//true //把這個屬性改為不可寫,會讓這個對象成為凍結對象. Object.defineProperty(nonConfigurable,"release",{writable : false}); console.log(Object.isFrozen(nonConfigurable) === true);//true //一個不可擴展的對象,值擁有一個訪問器,則它仍然是非凍結的. var accessor = {get food(){return "yum";}};//這里使用的是字面值法創建對象,默認可配置 Object.preventExtensions(accessor); console.log(Object.isFrozen(accessor) === false);//true //把這個屬性改為不可配置,會讓這個對象成為凍結對象. Object.defineProperty(accessor,"food",{configurable:false}); console.log(Object.isFrozen(accessor) === true);//true //使用 Object.freeze 是凍結一個對象的最方便的方法. var frozen = {1:81}; console.log(Object.isFrozen(frozen) === false);//true Object.freeze(frozen); console.log(Object.isFrozen(frozen) === true);//true //一個凍結對象也是一個密封對象 console.log(Object.isSealed(frozen) === true);//true //一個凍結對象也是一個不可擴展對象 console.log(Object.isExtensible(frozen) === false);//true })();Object.freeze 方法
MDN:
概述 Object.freeze() 方法可以凍結一個對象。 凍結對象是指那些不能添加新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性的對象。 也就是說,這個對象永遠是不可變的。該方法返回被凍結的對象。 語法 Object.freeze(obj) 參數 obj 將要被凍結的對象 描述 凍結對象的所有自身屬性都不可能以任何方式被修改。 任何嘗試修改該對象的操作都會失敗,可能是靜默失敗,也可能會拋出異常(嚴格模式中)。 數據屬性的值不可更改,訪問器屬性(有getter和setter)也同樣(但由于是函數調用,給人的錯覺是還是可以修改這個屬性)。 如果一個屬性的值是個對象,則這個對象中的屬性是可以修改的,除非它也是個凍結對象。
使用:
(function () { var obj = { prop:function(){}, foo:"bar" }; //可以添加新的屬性,已有的屬性可以被修改或刪除 obj.foo = "baz"; obj.lumpy = "woof"; delete obj.prop; Object.freeze(obj);//凍結 console.log(Object.isFrozen(obj) === true);//true //對凍結對象的任何操作都會失敗 obj.foo = "quux";//靜默失敗; obj.quaxxor = "the friendly duck";//靜默失敗 //在嚴格模式中會拋出 TypeError 異常 (function () { "use strict"; obj.foo = "sparky";//拋出 TypeError 異常 delete obj.quaxxor;//拋出 TypeError 異常 obj.sparky = "arf";//拋出 TypeError 異常 })(); //使用 Object.defineProperty方法同樣會拋出 TypeError 異常 Object.defineProperty(obj,"ohai",{value:17});//拋出 TypeError 異常 Object.defineProperty(obj,"foo",{value:"eit"});//拋出 TypeError 異常 })();
如該方法 MDN 的描述所述,倘若一個對象的屬性是一個對象,那么對這個外部對象進行凍結,內部對象的屬性是依舊可以改變的,這就叫淺凍結,若把外部對象凍結的同時把其所有內部對象甚至是內部的內部無限延伸的對象屬性也凍結了,這就叫深凍結。
淺凍結與深凍結
(function () { obj = { internal :{} }; Object.freeze(obj);//淺凍結 obj.internal.a = "aValue"; console.log(obj.internal.a);//"aValue" //想讓一個對象變得完全凍結,凍結所有對象中的對象,可以使用下面的函數. function deepFreeze(o){ var prop,propKey; Object.freeze(o);//首先凍結第一層對象 for(propKey in o){ prop = o[propKey]; if(!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)){ continue; } deepFreeze(prop);//遞歸 } } deepFreeze(obj); obj.internal.b = "bValue";//靜默失敗 console.log(obj.internal.b);//undefined })();
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91553.html
摘要:它將返回目標對象。封閉對象方法判斷一個對象是否被密封。為源對象為修改的屬性名或設置,同上方法返回一個給定對象自身可枚舉屬性的鍵值對數組方法返回指定對象上一個自有屬性對應的屬性描述符方法判斷兩個值是否是相同的值。 對象作為引用類型,工作中免不了復制對象,下面來看看克隆的方法 Object.assign() 方法用于將所有可枚舉屬性的值從一個或多個源對象復制到目標對象。它將返回目標對象。淺...
摘要:王國維在人間詞話里談到了治學經驗,他說古今之成大事業大學問者,必經過三種之境界。其中談到中凍結一個對象幾種由淺入深的實踐。王國維已先自表明,吾人可以無勞糾葛。總結本文先后介紹了關于凍結一個對象的三種進階方法。 王國維在《人間詞話》里談到了治學經驗,他說:古今之成大事業、大學問者,必經過三種之境界。 巧合的是,最近受 git chat / git book 邀請,做了一個分享。其中談到J...
摘要:王國維在人間詞話里談到了治學經驗,他說古今之成大事業大學問者,必經過三種之境界。其中談到中凍結一個對象幾種由淺入深的實踐。王國維已先自表明,吾人可以無勞糾葛。總結本文先后介紹了關于凍結一個對象的三種進階方法。 王國維在《人間詞話》里談到了治學經驗,他說:古今之成大事業、大學問者,必經過三種之境界。 巧合的是,最近受 git chat / git book 邀請,做了一個分享。其中談到J...
摘要:注意一旦把對象定義為防篡改,就無法撤銷了。使用阻止對象擴展注意嚴格模式下,不是而是報錯。使用凍結對象對于庫作者而言,凍結對象可防止有人修改庫的核心對象。 showImg(https://segmentfault.com/img/remote/1460000019753620); 前言:去年7月份在簡書寫的,發現后端、React中也有體現,覺得有必要在微信上分享下。 注意:一旦把對象定義...
閱讀 2161·2021-09-04 16:40
閱讀 1453·2021-08-13 15:07
閱讀 3605·2019-08-30 15:53
閱讀 3194·2019-08-30 13:11
閱讀 1069·2019-08-29 17:22
閱讀 1811·2019-08-29 12:47
閱讀 1469·2019-08-29 11:27
閱讀 2221·2019-08-26 18:42