JavaScript知识点回顾(二十五)——对象的不变性

225 阅读2分钟

这是我参与8月更文挑战的第二十五天,活动详情查看:8月更文挑战

不变性

有时候我们会希望属性或者对象是不可改变的。在ES5中,可以通过很多种方法来实现,然而所有方法创建的都是浅不变性,也就是说,它们只会影响目标对象和它的直接属性。如果目标对象引用了其他对象(数组、对象、函数等),其他对象的内容是不受影响的,仍然可变。

    myImmutableObject.foo;//[1,2,3]
    myImmutableObject.foo.push(4);
    myImmutableObject.foo;//[1,2,3,4];

假定代码中的myImmutableObject已经被创建并且是不可变的,但是为了保护它的内容myImmutableObjec.foo,还需要使用以下的方法让foo也不可变。

对象常量

结合writable:false和configurable:false就可以创建一个真正的常量属性(不可修改、重定义或者删除):

    var myObject={};
    Object.defineProperty(myObject,"FAVORITE_NUMBER",{
        value:2,
        writable:false,
        configurable:false
    });

禁止扩展

如果需要禁止一个对象添加新的属性并且保留已有的属性,可以用Object.preventExtensions():

    var myObject = {
        a : 2
    };
    Object.preventExtensions(myObject);
    myObject.b = 3;
    myObject.b;//undefined

在非严格模式下,创建b会静默失败,在严格模式下,会抛出TypeError错误。

密封

Object.seal()会创建一个“密封”的对象,这个方法实际上会在一个现有的对象上对应Object.preventExtensions()并且把所有现有的属性标记为configurable:false。 所以,密封之后不仅不能添加新的属性,也不能重新配置或者删除任何现有的属性(但可以修改属性值)

冻结

Object.freeze()会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal并把所有的“数据访问”属性标记为:writable:false,这样就无法修改它们的值。

这个方法是可以应用在对象上的级别最高的不可变性,它会禁止对于对象本身及其任意直接属性的修改(不过还是无法影响到这个对象引用的其他对象)。

“深度冻结”一个对象:先在这个对象上调用Object.freeze(),然后遍历所有它引用的对象,并在这些引用的对象上调用Object.freeze()。但是这样可能会无意中冻结其他共享对象。