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