如何在JavaScript/TypeScript中高效实现数据与操作分离?
TypeScript中数据与方法分离的优雅扩展方案
我刚学TypeScript不久,还是个新手。我有函数式编程背景,习惯把对象数据和方法分开写。比如下面这个简单的数据对象,后续会随着代码库扩展需要增强功能:
export interface Data { readonly value: number; } export function Data(value: number): Data { return { value }; } const data: Data = Data(2); console.info(data); // 输出 { value : 2 }
Data是我代码的核心模块,包含业务模型核心对象的所有数据。随着应用功能扩展,我想给它添加专用方法,目前想到三种方案:
方案一:使用“伴生对象”模式
export namespace Data { export function incr(self: Data): Data { return Data(self.value + 1); } } console.info(data); // 输出 { value : 2 } Data.incr(data);
这种方案能保持数据是简单对象,也支持扩展,但每次调用方法时语法太啰嗦。
方案二:使用接口模式
export namespace Data { export function Ops(self: Data) { return { self: self, incr(): Data { return Data(self.value + 1); } } } } const data_withops = Data.Ops({ value : 2 }); console.info(data_withops.self); // 输出 { value : 2 } data_withops.incr()
语法啰嗦的问题有所缓解,但还是得手动封装/解封装数据。
方案三:将操作注入数据
export interface Data { readonly value: number, incr(): Data } export function Data(value: number): Data { return { value, incr() { return Data(this.value + 1); } }; } const data: Data = Data(2); console.info(data); // 输出 { value : 2, incr : Function }
但这样会让对象体积变大,增加控制台输出、缓存和网络传输的负担。
有没有避开这些问题的实现方式?
我希望满足以下条件:
- 数据不膨胀:
console.info(data);输出{ value : 2 } - 对象使用者不用关心操作的“加载/卸载”
- 使用者有简洁的语法:可以直接调用
data.incr()
我本来以为原型方式可行,但尝试后没成功:
declare global { export interface Data { incr(this: Data): Data; } } Data.prototype.incr = function (this: Data): Data { return Data(this.value + 1); }; console.info(data); // 输出 { value : 2 } data.incr();
内容的提问来源于stack exchange,提问作者Coo LHibou
相关产品推荐
相关产品推荐

