冻结对象的方法三个

Javascipt中如果想使得对象或属性不能被修改,有很多种方式,下面由对象冻结的深浅程度,依次记录(由浅入深)。

1. Object.preventExtensions:不能增


Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。

    let obj = {}
    Object.preventExtensions(obj)
    obj.name = 'liderder'
    console.log(obj);

我们可以看到,obj中没有添加name属性。

同时,如果使用Object.defineProperty来增加对象属性,则会抛出异常:

    let obj = {}
    Object.preventExtensions(obj)
    Object.defineProperty(obj, "age", {
        value: 21
    })

并且,不可扩展对象的原型是不可变的,如果修改会抛出异常:

    let obj = {}
    Object.preventExtensions(obj)
    obj.__proto__ = {name:'liderder'}

那么我们是否可以修改对象的原有属性呢?答案是可以的

    let obj = {
        name: 'liderder'
    }
    Object.preventExtensions(obj)
    obj.name = 'li'
    console.dir(obj);

此时,我们想知道既然修改原有属性是可行的,那么删除这个属性呢?也是可以的!

    let obj = {
        name: 'liderder'
    }
    Object.preventExtensions(obj)
    delete obj.name 
    console.dir(obj);

总的来说 使用Object.preventExtensions()可以使一个对象不能够增加新的属性,但是可以对原有属性进行修改和删除操作。可以说这种方法冻结的不够存粹,那么有没有更纯粹的方法呢?就是下面这个

2. Object.seal():不能增删


Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。

使用这个方法冻结的对象,不可以增加新的属性,可以修改原有的属性,这些和Object.preventExtensions()一样,但是既然说它比Object.preventExtensions()更加纯粹,肯定有不一样的地方——Object.seal()还可以禁止删除原有属性。
与Object.preventExtensions()一样的地方就不做展示了,这里只做不一样的展示:

    let obj = {
        name: 'liderder'
    }
    Object.seal(obj)
    delete obj.name
    console.log(obj);


但是 虽然实现了对象属性的不可新增,不可删除,但是上面这两种方法都不能实现对象原有属性的不可修改,那么有没有比Object.seal()更加纯粹的冻结方法呢?
也是有的!

3. Object.freeze():不能增删改


使用Object.freeze()冻结的对象中的现有属性值是不可变的。用Object.seal()密封的对象可以改变其现有属性值。

    let obj = {
        name: 'liderder'
    }
    Object.freeze(obj)
    obj.name = 'li'
    console.log(obj);

我们可以发现,name属性的值并没有被删除掉。Object.freeze()方法使得被冻结的对象无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量。

但是实际上,以上的三种方法都由一个弊端,

可以通过改变原型对象,来为对象增加属性。【除非把obj的原型也冻结住】

如果属性值是对象,上面这些方法只能冻结属性指向的对象,而不能冻结对象本身的内容。

    let obj = {
        name: 'liderder',
        like: ['coding', 'eating', 'playing']
    }
    Object.freeze(obj)
    obj.like.push('liderder')
    console.log(obj);

我们可以看到,通过往obj.like中push新元素,是可以的。也就是说我们冻结的仅仅是like中保存的地址,但是这块地址指向的堆内存我们是可以修改的。还有就是在原型上新增属性,obj也是可以访问到的。

    let obj = {
        name: 'liderder',
    }
    Object.freeze(obj)
    obj.__proto__.age = 13
    console.log(obj);

那么有没有一种方法可以实现这样的一个需求,我要让一个对象彻底的冻结应该怎么办呢?

4. 手动实现一个冻结函数

function deepFreeze(obj) {
        if (typeof obj != 'object') {
            throw Error('Type Error!')
        }
        Object.freeze(obj);
        for (const key in obj) {
            if (Object.hasOwnProperty.call(obj, key)) {
                if (typeof obj[key] === 'object') {
                    deepFreeze(obj[key])
                }
            }
        }
    }


调用方法:

    let obj = {
        name: 'liderder',
        like: ['cat', 'dog', 'bat']
    }
    deepFreeze(obj)
    obj.like[2] = 'li'
    console.log(obj);



打印结果:

nice!(但是我们仍然可以通过向Object的显示原型对象上增加属性,并且通过obj访问。。。)
 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值