正經人一輩子都用不到的 JavaScript 方法總結 (二)

程式設計三昧發表於2021-08-25

前言

現在有這樣一個需求:用一個物件儲存某學生的各科成績,要求每次只能改變科目分數,不能再新增或者刪除科目。

分析一下,這個需求其實就是需要建立一個固定屬性的物件,其屬性不可增刪,但屬性值可更改。

有些同學可能就這麼開始了:

  • 首先,定義一個符合要求的物件:
// 宣告成績儲存物件
let reportObj = {};
// 給成績儲存物件新增科目,並設定科目屬性不可增刪,但科目成績可修改
Object.defineProperties(reportObj, {
    ChineseMark: {
        enumerable: true,
        writable: true,
        configurable: false,
        value: 60
    },
    EnglishMark: {
        enumerable: true,
        writable: true,
        configurable: false,
        value: 60
    }
});
  • 然後寫入成績:
// 存入科目成績
reportObj.ChineseMark = 99;
reportObj.EnglishMark = 95;
console.log(reportObj);  // {ChineseMark: 99, EnglishMark: 95}

刪除屬性來試試:

delete reportObj.ChineseMark;  // false
console.log(reportObj);  // {ChineseMark: 99, EnglishMark: 95}

貌似確實符合條件了,那麼再試試增加屬性吧:

reportObj.PhysicsMark = 100;
console.log(reportObj);  // {ChineseMark: 99, EnglishMark: 95, PhysicsMark: 100}

咋回事,怎麼突然就不太符合要求了呢?Object.defineProperties() 只能精確控制所增添的屬性的特質,但如果給物件新增屬性的話,它就無力控制了。

今天我們就用簡單的介面方法來實現一下這么蛾子需求 ︿( ̄︶ ̄)︿

Object.seal()

描述

seal 如果作動詞,那它的解釋就是“密封”:

image-20210825210254120

見名知意,Object.seal() 方法就是用來“密封”一個物件的,它阻止物件新增新屬性,並將物件所有的現有屬性標記為不可配置。當前屬性的值只要原來是可寫的就可以改變。

作用

通常,一個物件是可擴充套件的(可以新增新的屬性)。

密封一個物件會讓這個物件變的不能新增新屬性,且所有已有屬性會變的不可配置。屬性不可配置的效果就是屬性變的不可刪除,以及一個資料屬性不能被重新定義成為訪問器屬性,或者反之。但屬性的值仍然可以修改。

嘗試刪除一個密封物件的屬性或者將某個密封物件的屬性從資料屬性轉換成訪問器屬性,結果會靜默失敗或丟擲 TypeError(在嚴格模式 中最常見的,但不唯一)。

const object1 = {
    property1: 42
};

Object.seal(object1);
object1.property1 = 33;
console.log(object1.property1);
// expected output: 33

delete object1.property1; // cannot delete when sealed
console.log(object1.property1);
// expected output: 33

總結起來,Object.seal() 其實就是做了以下事情:

  • 設定Object.preventExtension(),禁止新增新屬性(絕對存在)
  • 設定configurable為false,禁止配置(絕對存在)
  • 禁止更改訪問器屬性(getter和setter)

語法

Object.seal(obj)

引數

引數 obj 代表將要被密封的物件。

返回值

被密封的物件。

實現需求

既然有這麼好用的方法,那我們當然要好好利用一番啦,終於可以完美實現文章開頭的需求了:

// 宣告成績儲存物件及其屬性
let reportObj = {   
    ChineseMark: 60,
    EnglishMark: 60
};
// 密封成績物件
let sealedReportObj = Object.seal(reportObj);
// 更改科目分數
sealedReportObj.ChineseMark = 99;
sealedReportObj.EnglishMark = 97;
console.log(sealedReportObj); // {"ChineseMark": 99, "EnglishMark": 97}

驗證一下:

// 增加屬性
sealedReportObj.PhysicsMark = 100;
console.log(sealedReportObj); // {"ChineseMark": 99, "EnglishMark": 97}

// 刪除屬性
delete sealedReportObj.ChineseMark; // false
console.log(sealedReportObj); // {"ChineseMark": 99, "EnglishMark": 97}

可以看到物件的屬性確實是增刪不了了,算是簡單實現了需求吧。

擴充套件

如果要判斷一個物件是否“密封”,我們可以使用 Object.isSealed() 方法:

Object.isSealed(sealedReportObj); // true

Object.freeze()

看到這裡,可能很多同學都想起了 Object.freeze() 方法,它的作用是用來凍結一個物件。實際作用就是字面意思:凍結一個物件,使其屬性和屬性值都不可更改。用來實現這個需求顯然是不合適的。

共同點

Object.seal()Object.freeze() 有以下共同點:

  • 作用的物件變得不可擴充套件,這意味著不能再新增新屬性。
  • 作用的物件中的每個元素都變得不可配置,這意味著不能刪除屬性。
  • 如果在 ‘use strict’ 模式下使用,這兩個方法都可能丟擲錯誤。

不同點

Object.seal() 能讓你修改屬性的值,但 Object.freeze() 不能。

總結

以上就是關於 Object.seal() 方法的一些簡單介紹和應用,以及它和 Object.freeze() 的異同點,希望能對大家有所幫助。

~

~本文完,感謝閱讀!

~

學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!

大家好,我是〖程式設計三昧〗的作者 隱逸王,我的公眾號是『程式設計三昧』,歡迎關注,希望大家多多指教!

你來,懷揣期望,我有墨香相迎! 你歸,無論得失,唯以餘韻相贈!

知識與技能並重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!

參考文件:

Object.seal()

Object.freeze()

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章