JS对象的拓展、封密、冻结

之前我傻傻的认为,js的对象很灵活,随意的添加属性和方法。但是我错了,js是可以控制对象的。
js对象有三大特性:扩展特性、密封特性、冻结特性

拓展特性

js对象可以添加新的属性,则这个对象是可扩展的。

Object.isExtensible 方法

Object.preventExtensions 方法

Object.isExtensible 方法

概述
Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
语法
Object.isExtensible(obj)
参数
obj 需要检测的对象

判断是否可以扩展,可以扩展返回true,不可以扩展返回false。如果没有设置的话,都是可以扩展的。

//新对象默认是可扩展的无论何种方式创建的对象,这里使用的是字面量方式
var empty = {a:1};
console.log(Object.isExtensible(empty));//true

//如果可以扩展,则可以添加其他的属性
if(Object.isExtensible(empty)){
    empty.b = "hello"
    empty.c = "word"
}

//等价于 使用属性描述符
empty = Object.create({},{
    "a":{
        value : 1,
        configurable : true,//可配置
        enumerable : true,//可枚举
        writable : true//可写
    }
});
console.log(Object.isExtensible(empty));//true

//对象是否可以扩展与对象的属性是否可以配置无关
empty = Object.create({},{
    "a":{
        value : 1,
        configurable : false,//不可配置
        enumerable : true,//可枚举
        writable : true//可写
    }
});
console.log(Object.isExtensible(empty) === true);//true

Object.preventExtensions 方法

概述
Object.preventExtensions() 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
语法
Object.preventExtensions(obj)
参数
obj 将要变得不可扩展的对象
描述
如果一个对象可以添加新的属性,则这个对象是可扩展的。
preventExtensions 可以让这个对象变的不可扩展,也就是不能再有新的属性。
需要注意的是不可扩展的对象的属性通常仍然可以被删除。
尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败,也可能会抛出 TypeError 异常(严格模式)。
Object.preventExtensions 只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性。

通过这个方法,把js对象变成不可扩展的

//新创建的对象默认是可扩展的
var empty = {};
console.log(Object.isExtensible(empty));//true
empty.a = 1;//添加成功

//将其变为不可扩展对象
Object.preventExtensions(empty);
console.log(Object.isExtensible(empty));//false

//使用传统方式为不可扩展对象添加属性
empty.b = 2;//静默失败,不抛出错误
empty["c"] = 3;//静默失败,不抛出错误

在这里也区分普通模式和严格模式,严格模式是会有错误抛出

密封特性

密封对象是指那些不可扩展的,且所有自身属性都不可配置的(non-configurable)对象。

或则说 密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。

Object.isSealed 方法

Object.seal 方法

Object.isSealed 方法

概述
Object.isSealed() 方法判断一个对象是否是密封的(sealed)。
语法
Object.isSealed(obj)
参数
obj 将要检测的对象
描述
如果这个对象是密封的,则返回 true,否则返回 false。

这个方法判断js对象是否是封密的,如果是返回true,不是返回false

    //新建的对象默认不是密封的
    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 方法

概述
Object.seal() 方法可以让一个对象密封,并返回被密封后的对象。
密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。
语法
Object.seal(obj)
参数
obj 将要被密封的对象
描述
通常情况下,一个对象是可扩展的(可以添加新的属性)。
密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。
属性不可配置的效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。
但属性的值仍然可以修改。
尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError 异常(严格模式)。
不会影响从原型链上继承的属性。但 proto ( ) 属性的值也会不能修改。

    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;//静默失败,属性没有删除成功

区分普通模式和严格模式,严格模式会抛出错误

冻结特性

一个对象是冻结的(frozen)是指它不可扩展,所有属性都是不可配置的(non-configurable),且所有数据属性(data properties)都是不可写的(non-writable)。

数据属性是值那些没有取值器(getter)或赋值器(setter)的属性。

或则说 冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。

Object.isFrozen 方法

Object.freeze 方法

Object.isFrozen 方法

概述
Object.isFrozen() 方法判断一个对象是否被冻结(frozen)。
语法
Object.isFrozen(obj)
参数
obj 被检测的对象
描述
一个对象是冻结的(frozen)是指它不可扩展,所有属性都是不可配置的(non-configurable),且所有数据属性(data properties)都是不可写的(non-writable)。数据属性是值那些没有取值器(getter)或赋值器(setter)的属性。

    //一个对象默认是可扩展的,所以他也是非冻结的.
    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 方法

概述
Object.freeze() 方法可以冻结一个对象。
冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。
也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
语法
Object.freeze(obj)
参数
obj 将要被冻结的对象
描述
冻结对象的所有自身属性都不可能以任何方式被修改。
任何尝试修改该对象的操作都会失败,可能是静默失败,也可能会抛出异常(严格模式中)。
数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。
如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。

    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 异常

浅冻结与深冻结

如果一个对象的属性是一个对象,那么对这个外部对象进行冻结,内部对象的属性是依旧可以改变的,这就叫浅冻结,若把外部对象冻结的同时把其所有内部对象甚至是内部的内部无限延伸的对象属性也冻结了,这就叫深冻结。

    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

猜你喜欢

转载自blog.csdn.net/u013513053/article/details/80611232