设计思路
- 使用
Object.defineProperty
管理可扩展性:通过 Object.defineProperty
方法可以精确控制对象属性的特性,包括是否可扩展。这使得我们能够在创建对象时就明确其可扩展性规则。
- 引入一个管理器对象:用于集中管理对象的可扩展性,方便在特定条件下修改对象的可扩展状态。这样可以避免在代码中分散地设置对象的可扩展性,增强代码的可维护性。
- 性能和内存优化:尽量减少不必要的对象创建和属性操作,对于频繁访问的对象,可以缓存其可扩展性状态,避免重复查询。
核心代码片段
// 可扩展性管理器
const extensibilityManager = {
objects: {},
// 注册对象及其初始可扩展性
registerObject: function (obj, isExtensible) {
this.objects[obj] = {
isExtensible: isExtensible,
originalState: Object.getOwnPropertyDescriptors(obj)
};
Object.preventExtensions(obj);
if (isExtensible) {
Object.defineProperty(obj, Symbol('__isExtensible'), {
value: true,
enumerable: false,
configurable: false
});
}
},
// 在特定条件下使对象可扩展
makeExtensible: function (obj) {
if (!this.objects[obj]) {
throw new Error('Object not registered');
}
if (this.objects[obj].isExtensible) {
Object.defineProperty(obj, Symbol('__isExtensible'), {
value: true,
enumerable: false,
configurable: false
});
Object.defineProperty(obj, Symbol('__originalState'), {
value: this.objects[obj].originalState,
enumerable: false,
configurable: false
});
Object.defineProperty(obj, Symbol('__restore'), {
value: function () {
const originalState = this[Symbol('__originalState')];
Object.keys(originalState).forEach(key => {
Object.defineProperty(this, key, originalState[key]);
});
Object.preventExtensions(this);
Object.defineProperty(this, Symbol('__isExtensible'), {
value: false,
enumerable: false,
configurable: false
});
},
enumerable: false,
configurable: false
});
Object.defineProperties(obj, {
...this.objects[obj].originalState,
...Object.getOwnPropertyDescriptors(obj)
});
Object.enhanceExtensions(obj);
}
},
// 恢复对象到不可扩展状态
restoreObject: function (obj) {
if (!this.objects[obj]) {
throw new Error('Object not registered');
}
if (this.objects[obj].isExtensible) {
const restoreFunction = obj[Symbol('__restore')];
if (restoreFunction) {
restoreFunction.call(obj);
}
}
}
};
// 示例用法
const myObject = {};
extensibilityManager.registerObject(myObject, true);
// 在特定条件下
if (someCondition) {
extensibilityManager.makeExtensible(myObject);
myObject.newProperty = 'new value';
} else {
extensibilityManager.restoreObject(myObject);
}