對象屬性防篡改

防篡改

防止對象創(chuàng)建后,修改對象的結(jié)構(gòu)內(nèi)容

  • 在相關(guān)級(jí)別的防篡改模式下,如果違背其設(shè)置要求,不會(huì)報(bào)錯(cuò),屬性對象不會(huì)改變
    但是在嚴(yán)格模式('use strict')下,會(huì)報(bào)錯(cuò)
  • 在ES5中,如果設(shè)置防篡改的相關(guān)方法的參數(shù)不是一個(gè)對象(一個(gè)原始值),結(jié)果會(huì)導(dǎo)致 TypeError,而在ES2015中,非對象參數(shù)將被視為普通對象,并被簡單地返回。

三個(gè)級(jí)別:

1、防擴(kuò)展

禁止給對象添加任何新屬性(不可擴(kuò)展,可刪除,可修改),其本質(zhì)為:
Object.preventExtensions(obj),返回值為對象自身(引用)

var obj = { a: 1 };

// 對象初始的屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: true, enumerable: true, configurable: true }

// 設(shè)置防擴(kuò)展后的對象屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: true, enumerable: true, configurable: true }

可以看出,防擴(kuò)展,并沒有對對象的屬性描述符進(jìn)行二次修改

可以使用Object.isExtensible()判斷一個(gè)對象是否是可擴(kuò)展對象

Object.preventExtensions()能夠擴(kuò)展原型對象上的屬性

preventExtensions()只是針對對象中第一層的屬性進(jìn)行防擴(kuò)展,對于后面深層次的對象屬性無法進(jìn)行防擴(kuò)展

var obj = { a: 1, b: { name: "sun" } };

Object.preventExtensions(obj); // 設(shè)置防擴(kuò)展

obj.c = 100; // 為對象obj增加屬性 c
obj.b.age = 20;  // 為obj中的b對象增加屬性 age

console.log(obj);
//  { a: 1, b: { name: 'sun', age: 20 } }
// 屬性c添加失敗,而對obj中的b對象增加屬性 age 仍然有效

2、封閉

seal在防擴(kuò)展的基礎(chǔ)上,再禁止刪除現(xiàn)有的屬性(不可擴(kuò)展,不可刪除,可修改(writable為true的前提下)),其本質(zhì)為:

  • 設(shè)置Object.preventExtension(),禁止添加新屬性
  • 設(shè)置configurable為false,禁止更改配置
  • 禁止更改訪問器屬性(getter和setter)

Object.seal(obj) 返回值為對象自身(引用)

var obj = { a: 1 };

// 對象初始的屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: true, enumerable: true, configurable: true }

// 設(shè)置封閉后的對象屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: true, enumerable: true, configurable: false }

可以看出,設(shè)置封閉之后,將對象的屬性描述符的configurable改為了false,

可以使用Object.isSealed()判斷一個(gè)對象是否是封閉對象

一個(gè)封閉對象,必然是一個(gè)不可擴(kuò)展對象,不可擴(kuò)展的空對象也是一個(gè)封閉對象

Object.seal()能夠修改原型對象上的屬性

freeze()是淺封閉(與淺拷貝類似),只是封閉了對象中第一層的屬性,對于后面的對象屬性無法進(jìn)行封閉

3、凍結(jié)

禁止對對象做任何修改(不可擴(kuò)展,不可刪除,不可修改),其本質(zhì)為:

  • 設(shè)置Object.preventExtension(),禁止添加新屬性
  • 設(shè)置writable為false,禁止修改值
  • 設(shè)置configurable為false,禁止更改配置
  • 禁止更改訪問器屬性(getter和setter)

Object.freeze(obj) 返回值為對象自身(引用)

var obj = { a: 1 };

// 對象初始的屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: true, enumerable: true, configurable: true }

// 設(shè)置凍結(jié)后的對象屬性描述符
console.log(Object.getOwnPropertyDescriptors(obj));
//  a: { value: 1, writable: false, enumerable: true, configurable: false }

可以看出,設(shè)置凍結(jié)對象,則對象的屬性描述符的writable、configurable都改為了false

可以使用Object.isFrozen()判斷一個(gè)對象是否是凍結(jié)對象

一個(gè)凍結(jié)對象,必然是一個(gè)封閉對象,不可擴(kuò)展空對象也是一個(gè)凍結(jié)對象

Object.freeze()能夠修改原型對象上的屬性

freeze()是淺凍結(jié)(與淺拷貝類似),只是凍結(jié)了對象中第一層的屬性,對于后面的對象屬性無法進(jìn)行凍結(jié)

實(shí)現(xiàn)深度防擴(kuò)展、深封閉、深凍結(jié)

  • 深度防擴(kuò)展
Object.deepPreventExtensions = function (obj) {
  // Object.keys無法獲取不可枚舉的屬性
  // Object.getOwnPropertyNames獲取所有屬性
  var _keys = Object.getOwnPropertyNames(obj);
  if (_keys.length) {
    _keys.forEach(k => {
      var _value = obj[k];

      // 如果值為對象,則繼續(xù)凍結(jié)
      if (typeof _value === 'object' && _value !== null) {
        Object.deepPreventExtensions(_value);
      }
    })
  }

  return Object.preventExtensions(obj);
}
  • 深封閉
// 深度封閉
Object.deepSeal = function (obj) {
  // Object.keys無法獲取不可枚舉的屬性
  // Object.getOwnPropertyNames獲取所有屬性
  var _keys = Object.getOwnPropertyNames(obj);
  if (_keys.length) {
    _keys.forEach(k => {
      var _value = obj[k];

      // 如果值為對象,則繼續(xù)凍結(jié)
      if (typeof _value === 'object' && _value !== null) {
        Object.deepSeal(_value);
      }
    })
  }

  return Object.seal(obj);
}
  • 深凍結(jié)
// 深度凍結(jié)
Object.deepFreeze = function (obj) {
  // Object.keys無法獲取不可枚舉的屬性
  // Object.getOwnPropertyNames 能獲取所有屬性
  var _keys = Object.getOwnPropertyNames(obj);
  if (_keys.length) {
    _keys.forEach(k => {
      var _value = obj[k];

      // 如果值為對象,則繼續(xù)凍結(jié)
      if (typeof _value === 'object' && _value !== null) {
        Object.deepFreeze(_value);
      }
    })
  }

  return Object.freeze(obj);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容