浅谈 JS 对象之扩大、密封及凝结三大特征

  • 扩大特征

    • Object.isExtensible 要领

    • Object.preventExtensions 要领

  • 密封特征

    • Object.isSealed 要领

    • Object.seal 要领

  • 凝结特征

    • Object.isFrozen 要领

    • Object.freeze 要领

      • 浅凝结深凝结

扩大特征

假如一个对象能够增加新的属性,则这个对象是可扩大的。
让这个对象变的不可扩大,也就是不能再有新的属性

我们都晓得,我们能够经由过程属性形貌符建立属性不可设置对象 怎样让对象属性不可设置或罗列,
在这里我们能够建立不可扩大属性的对象

Object.isExtensible 要领

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
})();
    原文作者:Tomson
    原文地址: https://segmentfault.com/a/1190000003894119
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞