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