扩展特性segmentfault
Object.isExtensible
方法函数
Object.preventExtensions
方法测试
密封特性spa
Object.isSealed
方法prototype
Object.seal
方法code
冻结特性对象
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
那么咱们如何让一个对象变成不可扩展:
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)对象。
或则说 密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能能够修改已有属性的值的对象。
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 })();
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)的属性。
或则说 冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。
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 })();
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 })();