js冻结一个对象Object.defineProperty-Object.freeze-Object.seal-Object.preventExtensions

1,125 阅读5分钟

1.jpg 如果在开发中我不想让别人对obj对象添加或删除元素 可以砸子做?

当该属性的configurable键值为true时该属性的描述才能被修改 同时该属性也能从对应的对象上被删除
就是说如果configurable值为false时属性就无法从对象上面删除 这个方法 仅能使对象内的 元素无法被删除 依旧可以在新对象中添加新的对象
看代码示例

Object.defineProperty(obj,"prop",{
     configurable:false,  //configurable属性为true时 该属性的秒速符才能被修改 同时该属性也能从对应的对象上被删除 
     enumerable:false,    //enumerable  属性为true时 该属性才会出现在对象的枚举属性中
     writable:false,      //表示 是否可以修改属性的值 
     value:""             //该属性的值 可以是任何有效的js 值(数值,对象,函数)
})
//这样设置以后 prop属性就变成了不能删除 不能重新修改特性 不可枚举 不能修改的属性值的属性
 //  示例代码 
    const obj = {name:"东东"}
    Object.defineProperty(obj,"name",{
        writable:false,
        configurable:false
    })
    // 修改 
    obj.name = "收购腾讯";
    console.log(obj.name);      //东东 
    // 添加新的属性  
    obj.address = "青岛"
    console.log(obj.address);   //青岛

Object.freeze(person);

冻结的对象既不可扩展,又是密封的,而且对象,数据属性的[ [Writable] ]特性会被设置为false。
如果定义[ [Set] ]函数,访问器属性仍然是可写的。ES5定义的Object. freeze()方法可以用来冻结对象。 代码所示

var person = {
        name: "大黄"
    };
    Object.freeze(person);     //冻结了这个对象 
    person.age = 18;           //新添加一个age属性 没有起效果
    console.log(person.age);   //undefined
    delete person.name;        //删去name属性 没有起效果
    console.log(person.name);  //"大黄"
    person.name = "咪咪";      //改变已有的属性 没起到效果 
    console.log(person.name);  //"大黄"
    // Object. isFrozen()方法用于检测冻结对象。因为冻结对象既是密封的又是不可扩展的,
    // 所以用Object.isExtensible()和Object.isSealed ()检测冻结对象将分别返回false和true。
    var person = {
        name: "老王"
    };
    alert(Object.isExtensible(person)); //true
    alert(Object.isSealed(person));     //false
    alert(Object.isFrozen(person));     //false
    Object.freeze(person);
    alert(Object.isExtensible(person)); //false
    alert(Object.isSealed(person));     //true
    alert(Object.isFrozen(person));     //true

Object.seal()

这个方法封闭(密封)一个对象 阻止添加新属性 并将所有的属性标记为不可配置
当前属性的值 只要原来的可写的 就可以改变
一个对象是可拓展的(可以添加新的属性)
1 密封一个对象会让这个对象变得不能添加新属性
且所有已有的属性会变得 不可配置(属性不可配置的效果 即属性不可删除)
2 以及一个数据属性 不能被重新定义成为访问器属性 或者反之
但属性的值仍然可以修改
3 尝试删除一个密封对象的属性或者
将某个密封对象的属性从数据属性 转换为访问器属性 结果会静默抛出TypeError
看示例代码

  var person = {
        name: "收购百度"
    }
    Object.seal(person);     //封闭这个对象

    person.age = 19;
    console.log(person.age); //undefined
                             //无法给密封对象添加属性
    delete person.name;
    console.log(person.name);//收购百度
                             //无法修改密封对象中的属性。
    //使用Object.isSealed() 方法确定对象是否被密封 而且由于被密封的对象不可扩展,
    //所以Object.isExtensible() 检测也会返回 false。
    var person = {
        name: "老王"
    }
    Object.seal(person);

    console.log(Object.isSealed(person)); //true
    console.log(Object.isExtensible(person)); //false

es5的防止篡改对象

但是要注意,一旦把对象定义为防篡改对象,就无法撤销了。
默认情况下,所有对象都是可以扩展的。也就是说,任何时候都可以向对象中添加属性和方法

  //Object.preventExtensions() 方法
            //1 改变这一行为 不能再添加属性或者方法。
            //2 虽然不能扩展该对象,但是不影响原有的属性,原有的属性仍然可以进行修改或者删除。
            var person = {
                name: "收购腾讯"
            }
            Object.preventExtensions(person); //将person设置为不可扩展对象
            person.money = 14;
            console.log(person);              //{name: "收购腾讯"}
            console.log(person.money);        //undefined
            person.name = "收购阿里 ";
            console.log(person.name);         //收购阿里
    //使用 Object.isExtensible() 方法可以确定该对象是否为可扩展对象。    
        var p = {
            name: "老王"
        }
        console.log(Object.isExtensible(p)); //ture
        Object.preventExtensions(p);         //将p设置为不可扩展对象
        console.log(Object.isExtensible(p)); //false

es6 常量冻结

  //常量冻结 
    const esObj = {         //这里是一个对象
        name:"es6",
        year:2015
    }
    //Object.freeze(esObj);  //加上这一句 则下面的log{name:"es6",year:2015}
    esObj.name ="es2015";
    console.log(esObj)       //{name:"es2015", year:2015}

    const arr = ['es6','es7','es8'];   //这是一个数组 
    //Object.freeze(arr)     //冻结
    arr[0] = 'es2015'
    console.log(arr)         //["es2015","es7","es8"]
    /*
     上面的代码说明 对象和数组 这类引用数据类型 因为在栈内存中存的引用地址 所以其堆内存中的内容是会被改变的 
     若不想被改变 加 freeze()方法冻结 
    */
   const esObj ={
    name:"es6",
    year:'2015',
    extension:["es7","es8","es9"]
   }
   Object.freeze(esObj);
   esObj.extension[0] = "es2016"
   console.log(esObj)
   /*
   {name: "es6", year: "2015", extension: Array(3)}
    extension: Array(3)
    0: "es2016"
    1: "es8"
    2: "es9"
   */
   //说明freeze的冻结只是 浅层次的 内部的数组还是会改变 这!!! 
   //看下面封装一下函数  定义一个myFreeze
   function myFreeze(obj){
       Object.freeze(obj);
       Object.keys(Obj).forEach(function(key){  //Object.keys()方法会返回一个当前对象属性所组成的数组
           if(typeof obj[key] === "object"){    //如果key对应的属性的值是一个对象的话
            myFreeze(obj[key])                  //那么再次冻结 递归 再次执行 
           }
       })
   }
   
   //方法2
      function meFreeze(obj){
        //判断参数是否为object 
        if(obj instanceof Object){
            for(let key in obj){
                if(obj.hasOwnProperty(key)){
                    Object.defineProperty(obj,key,{
                        writable:false,  //只读属性
                    })
                    Object.seal(obj)     //封闭对象 
                }
            }
        }
        return obj
   }

注意:在对防篡改对象或者冻结对象时,在非严格模式和严格模式下,抛出的结果不一样 如果有错误或者不严谨的地方,请留言备注,十分感谢,对作者也是一种鼓励。