场景
我有个类叫Stuff,里面有个_options配置属性,它是对外隐藏的,在实例类的时候通过构造函数参数更新它。但是我不想用户访问这个实力时候需要stuff.options.xx这样处理。
这种方式Stuff添加个对options的get拦截函数就可以了,例如
class Stuff{
//省略其他代码
get options(){
return this._options
}
}
但是如果我需要对这个_options下面的所有属性都添加get或者set呢?手动一个个加很明显不大友好,目前vscode只支持对一级属性快捷键添加get set
装饰器
我第一时间想到的是装饰器,多方便呀,直接@xx就可以处理
然鹅,不行
装饰类不可以访问类实力,装饰类拿到的是类本身,如果用Object.definePrototype来给类Stuff添加name属性的get,必须得用Stuff.name访问才会触发get函数,这明显不符合我的需要
嗯~~~!!!!????
那就用类继承吧,把做这个动作的功能封装起来,ts的代码如下:
基础类
class BaseWithOptions {
protected _options: { [key: string]: any };
constructor(options: { [key: string]: any } = {}) {
this._options = options;
// 调用静态方法来设置getter
this.constructor.definePropertyGetters(this);
}
// 静态方法,用于在子类实例化时设置getter
static definePropertyGetters(instance: any) {
for (const key in instance._options) {
if (instance._options.hasOwnProperty(key)) {
Object.defineProperty(instance, key, {
get(): any {
return instance._options[key];
},
// 如果需要,也可以添加setter
// set(value: any): void {
// instance._options[key] = value;
// }
});
}
}
}
}
拓展类
// 继承自BaseWithOptions的类
class Stuff extends BaseWithOptions {
constructor(options: { [key: string]: any } = {}) {
super(options);
// 这里不需要再调用definePropertyGetters,因为已经在BaseWithOptions的构造函数中调用了
}
}
const stuff = new Stuff({ name: "newname", age: 100 });
console.log("stuff", stuff, stuff.name); // 输出 stuff Stuff { ... } newname
console.log("stuff age", stuff.age); // 输出 stuff age 100
总结
在这个例子中,BaseWithOptions
类有一个_options
属性和一个constructor
,后者接受一个options
对象作为参数。BaseWithOptions
类还包含一个静态方法definePropertyGetters
,该方法遍历_options
对象的属性,并为每个属性在实例上定义一个getter。当BaseWithOptions
的子类(如Stuff
)被实例化时,会调用super(options)
来调用基类的构造函数,并在此过程中设置getter。因此,子类的实例可以直接访问options
对象中的属性