<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【每日一題】如何設置對象的屬性不可添加或刪除

          共 5017字,需瀏覽 11分鐘

           ·

          2021-09-02 01:55

          人生苦短,總需要一點儀式感。比如學前端~

          如何設置對象不可添加或者刪除屬性

          一共有如下幾種方式:

          1. Object.defineProperty()
          2. Object.seal()
          3. Object.freeze()
          4. Proxy

          前置知識:對象屬性的數據描述符

          對象的屬性有幾個數據描述符:

          1. configurable 表示是否可配置,作用有2:
            • 屬性數據描述符是否可被改變 (除value和writable特性外的其他描述符)
            • 屬性是否可被刪除
          2. enumerable: 表示屬性是否可枚舉
          3. value 表示屬性的值
          4. writable 表示屬性的值是否可以修改

          默認值

          使用 Object.defineProperty() 添加的屬性值是不可修改(immutable)的。
          這主要和幾個屬性的默認值有關:

          const object1 = {};

          Object.defineProperty(object1, 'property1', {
          });
          // 不填寫屬性數據描述符的前提下,獲取生成的描述符默認值
          console.log(Object.getOwnPropertyDescriptor(object1, 'property1'))
          屬性描述符默認值

          查看對象屬性描述符

          Object.getOwnPropertyDescriptor() 方法,用來查看指定對象上某個非原型屬性的屬性描述符。

          特別記憶:

          對象屬性的 configurable 鍵值為 true 時,該屬性的描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。

          當試圖改變不可配置屬性的值時 (除了 value 和 writable 屬性之外) ,會拋出TypeError,除非當前值和新值相同。

          嘗試修改導致的報錯

          實現方法講解如下

          defineProperty、defineProperties

          根據上邊屬性描述符的作用我們可以推斷,如果將 configurable 的值為 false 的時候,屬性就無法從對象上刪除。

          Object.defineProperty(obj, "name", {
            configurablefalse// 當且僅當該屬性的 configurable 鍵值為 true 時,該屬性的描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。
            enumerablefalse// 當且僅當該屬性的 enumerable 鍵值為 true 時,該屬性才會出現在對象的枚舉屬性中。
            writablefalse// 表示是否可以修改屬性的值。
            value"小石頭"// 該屬性(name)對應的值??梢允侨魏斡行У?JavaScript 值(數值,對象,函數等)。
          });

          像上邊代碼這樣設置之后,name屬性就變成了不能刪除、不可重新修改特性、不可枚舉、不能修改屬性值的狀態(tài)。

          但是只這么設置的話,目前obj對象只實現了元素無法被刪除,我們還是能往對象中添加新的屬性。

          obj.address = "beijing";
          console.log(obj); // { address: "beijing", name: "小石頭" }

          Object.seal()

          一個對象是可擴展的(可以添加新的屬性)。而Object.seal()方法會封閉一個對象:

          • 阻止添加新屬性
          • 并將所有現有屬性標記為不可配置(即不可刪除和不可修改屬性的某幾個數據描述符)。
          • 不過,當前屬性的值只要原來是可寫的就可以改變。也就是說屬性的值仍然可以修改。

          嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出 TypeError (在嚴格模式中最常見的,但不唯一)。

          const obj = { name"小石頭" };
          Object.getOwnPropertyDescriptors(obj);
          查看屬性數據描述符

          封閉對象:

          Object.seal(obj);
          Object.getOwnPropertyDescriptors(obj);
          封閉普通對象后的效果

          這時如果再去配置就失效了

          Object.defineProperty(obj, "name", {
            configurabletrue
          });
          Object.getOwnPropertyDescriptors(obj);
          configurable 已經不可以配置、屬性也不可刪除了

          同時也沒法添加新屬性了

          obj.age = 18
          對象也不可添加新屬性了

          Object.freeze()

          Object.freeze() 方法可以凍結一個對象。凍結后的對象有如下特點:

          • 一個被凍結的對象再也不能被修改;
          • 不能向凍結對象添加新的屬性,
          • 不能刪除凍結對象的已有屬性,
          • 不能修改凍結對象已有屬性的可枚舉性、可配置性、可寫性以及不能修改已有屬性的值。
          • 此外,凍結一個對象后該對象的原型也不能被修改。

          ??注意:Object.freeze()方法實現的是淺凍結

          const obj = {
            name"小石頭",
            info: {
              address"beijing",
            },
          };
          const freezeObj = Object.freeze(obj); // freeze()返回和傳入的參數相同的對象
          // 不能修改凍結對象已有屬性值
          freezeObj.name = "石頭姐";
          console.log(freezeObj.name); // 仍然是小石頭
          // 不能往凍結對象新加內容
          freezeObj.newName = '石頭姐'
          console.log(freezeObj.name); // undefined,增加失敗
          // 刪除凍結對象的已有屬性也不成功
          delete freezeObj.name
          console.log(freezeObj.name); // 仍然是小石頭
          凍結后的對象和原對象看上去沒啥區(qū)別

          嚴格模式下,操作凍結對象的屬性會報錯

          ("use strict");
          freezeObj.name = "石頭姐"// TypeError
          //Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'
          報錯

          深層嵌套的對象沒有被凍結:

          // 在這里,info 是沒有被凍結的
          freezeObj.info.newName = "BJ";
          console.log(freezeObj.info.newName); // BJ

          ES6 的 Proxy 方法

          ?

          Proxy 可以理解成,在目標對象之前架設一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。
          From:https://es6.ruanyifeng.com/#docs/proxy

          ?

          它在 API 使用者和對象之間扮演了一個中間人的角色。我們可以使用 Proxy 來控制被訪問的底層對象的屬性的行為。

          const target = {
            a"我是不能刪除的",
            b"我是不能修改的",
            c"也不能添加,我只有3個元素",
          };
          const lockTraget = new Proxy(target, {
            // 攔截對象屬性的設置,返回false不讓設置屬性
            set(target, property, value) {
              console.log("攔截修改、新增操作", target, property, value);
              return false;
            },
            // 攔截delete proxy[propKey]的操作,返回false不讓刪除
            deleteProperty(target, property) {
              console.log("攔截刪除操作");
              return false;
            },
            // 攔截Object.defineProperty()、Object.defineProperties()操作,
            defineProperty(target, property, descriptor) {
              console.log("defineProperty()");
              return false;
            },
          });
          lockTraget.newName = "石頭姐";
          console.log(lockTraget.newName); // undefined,新增失敗

          delete lockTraget.a;
          console.log(lockTraget.a); // "我是不能刪除的", 刪除失敗

          lockTraget.b = '小石頭'
          console.log(lockTraget.b); // "我是不能修改的", 修改失敗

          最后,我們掙扎的想用Object.defineProperty修改屬性數據描述符,也報錯了


          END
          愿你歷盡千帆,歸來仍是少年。


          讓我們一起攜手同走前端路!

          關注公眾號回復【加群】即可

          ● 工作中常見頁面布局的n種實現方法

          ● 三欄響應式布局(左右固寬中間自適應)的5種方法

          ● 兩欄自適應布局的n種實現方法匯總

          ● 工作中常見的兩欄布局案例及分析

          ● 垂直居中布局的一百種實現方式

          ● 常用九宮格布局的幾大方法匯總

          ● 為什么操作DOM會影響WEB應用的性能?

          ● 移動端滾動穿透的6種解決方案

          ● Vue + TypeScript 踩坑總結

          瀏覽 139
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  四虎伊人在线 | 操逼视频软件 | 97人人爱 | 五月婷丁香久久 | 黄色成人在线免费观看 |