几步操作,让你的 JS 类属性安全无忧且不可更改!

2024-08-24 14:00:12 浏览数 (2)

对象属性控制与锁定

  • 使用Object.defineProperty方法创建属性并控制其行为。
    • Object.defineProperty允许精确地定义对象的属性,通过属性描述符可以控制属性的可枚举性、可写性、可配置性等特性。
    • 例如,可以创建一个只读属性、不可枚举属性等,实现对对象属性行为的精细控制。
  • 使用Object.seal方法锁定对象。
    • Object.seal用于密封一个对象,这意味着不能向该对象添加新属性,并且现有属性的可配置性被设置为 false,即不能删除或重新配置现有属性。
    • 确保对象的结构在特定的上下文中保持稳定,防止意外的属性修改或添加。
  • 使用Object.freeze方法冻结对象。
    • Object.freeze会使对象完全不可变,不仅不能添加新属性、删除现有属性或重新配置现有属性,而且不能修改现有属性的值。
    • 提供了更高程度的对象稳定性和安全性。

综上所述,通过结合使用Object.definePropertyObject.sealObject.freeze方法,可以实现对对象属性的精细控制和对象结构的严格锁定,以满足特定的编程需求。尤其是在需要确保数据的完整性和安全性的场景中,这些方法非常有用。

我们来看一段代码

代码语言:javascript复制
/* 定义一个名为 aGoods 的对象 */
var aGoods = {
    // 初始化 pic 属性为空字符串
    pic: '',
    // 初始化 title 属性为空字符串
    title: '',
    // 初始化 desc 属性为空字符串
    desc: '',
    // 初始化 sellNumber 属性为 1
    sellNumber: 1,
    // 初始化 favorTate 属性为 2
    favorTate: 2,
    // 初始化 price 属性为 3
    price: 3,
};

// 定义 UiGoods 类
class UiGoods {
    // 构造函数,接收一个参数 g
    constructor(g) {
        // 克隆 g 对象,确保 this.data 指向的是一个全新的对象,而非传入的 g 对象的引用
        g = {...g}

        // 冻结 g 对象,确保其属性不可被修改
        Object.freeze(g);

        // 定义 data 属性
        // 配置属性描述符,设置 configurable 为 false,使得属性不可被删除或修改
        Object.defineProperty(this, 'data', {
            configurable: false,
            // 定义 set 方法,当尝试修改属性值时,抛出错误
            set: function () {
                throw Error('不能修改');
            },
            // 定义 get 方法,访问属性时返回冻结的 g 对象,确保 data 属性不能被外部修改
            get: function () {
                return g;
            }
        });

        // 定义 choose 属性
        // 内部变量,初始化为 0
        var internalChooseVal = 0;
        // 配置 choose 属性描述符
        Object.defineProperty(this, 'choose', {
            configurable: false,
            // 定义 getter,访问 choose 属性时返回 internalChooseVal 
            get: function () {
                return internalChooseVal;
            },
            // 定义 setter,当设置 choose 属性时
            set: function (v) {
                // 确保输入为数字
                if (typeof v!== 'number') {
                    throw Error('只能是数字');
                }
                // 确保值为整数且不小于 0
                if (v < 0 || Math.floor(v)!== v) {
                    throw Error('只能是整数并且不能小于0');
                }
                // 设置 internalChooseVal 的值
                internalChooseVal = v;
            }
        });

        // 定义 totalPrice 属性
        Object.defineProperty(this, 'totalPrice', {
            // 配置 totalPrice 属性的 getter,计算 choose 属性和 data 属性中 price 值的乘积
            get: function () {
                return this.choose * this.data.price;
            }
        });

        // 设置实例的 a 属性为 1
        this.a = 1;

        // 密封当前实例,使得其属性不可被删除,但属性值仍然可以被修改
        Object.seal(this);
    }

    // 定义 isChoose 属性,检查 choose 属性是否大于 0
    get isChoose() {
        return this.choose > 0;
    }
}

// 密封 UiGoods 类的原型,确保原型对象的属性和方法不能被修改或删除
Object.seal(UiGoods.prototype);

// 创建一个 UiGoods 实例
var g = new UiGoods(aGoods);

// 打印实例 g 的信息
console.log(g);

以下是代码中涉及到的知识点

对象创建和克隆

  • 代码开始部分展示了创建一个名为 aGoods 的对象。在 UiGoods 类的构造函数中,使用对象扩展运算符 ... 克隆 aGoods 对象,确保每个 UiGoods 实例都有自己的 data 属性副本。

Object.defineProperty

  • 在 UiGoods 类中使用 Object.defineProperty 方法来定义 data、choose 和 totalPrice 属性。这个方法允许精确地控制属性的读、写、可配置性和可枚举性。

对象封装

  • 通过使用 set 和 get 访问器,UiGoods 类封装了数据。data 和 totalPrice 属性被设置为只读,choose 属性只能通过特定的规则进行设置,增强了对象的安全性和数据完整性。

Error 抛出

  • 在尝试设置 data 属性或设置 choose 属性为无效值(如非数字或违反约束)时,set 访问器会抛出错误,提供清晰的错误反馈。

数据计算

  • totalPrice 属性是一个计算属性,其值基于 choose 和 data.price 的乘积。每次访问 totalPrice,它都会动态地返回最新的计算值。

对象锁定

  • 在构造函数的末尾,使用 Object.seal 锁定当前实例。这确保了所有属性都保持其当前状态,不能被删除,但仍然允许修改属性值。

getter 方法

  • 为 isChoose 属性创建了一个 getter 方法,这样可以通过简单地访问 g.isChoose 来检查 g.choose 的状态。

0 人点赞