链式调用与proxy

tags:知乎分享地址
知乎地址:https://zhuanlan.zhihu.com/p/189746698
思否地址:https://segmentfault.com/a/1190000023694003
链式调用虽然快乐,可每个方法后面的 return this 略显繁琐与丑陋,括号与引号也未免太多。
例如下面这个简单的logger
TypeScript
new Logger() .addLabel("warn", "l4", "登录", "游客", "error") .addContent("失败") .addContent("密码不对") .end();
你可能已经对这样的封装习以为常了,但其实他还能这样写!
TypeScript
Log.warn.l4.label("登录", "游客").log("失败").error.密码不对;
我觉得后者有一种简洁美
具体实现如下
TypeScript
class Logger { label: string[] = []; content: unknown[] = []; addLabel(...label: string[]) { this.label.push(...label); return this; } addContent(content: unknown) { this.content.push(content); return this; } end() { // 做一些存储打印之类的操作 console.log(this); } } function getLog() { const logger = new Logger(); /** 访问链路 */ const propertyLink: (string | number | symbol)[] = []; const self = (new Proxy(/** 目标不重要,因为实际上使用 target */ getLog, { get(target, property, receiver) { propertyLink.push(property); // console.log(property); if (/** 表等级用 */ typeof property === "string" && /l\d+/.test(property)) { logger.addLabel(property); } else if (/** 直接添加标签 */ typeof property === "string" && ["warn", "error"].includes(property)) { logger.addLabel(property); } else if (/** 可以调用的方法 */ typeof property === "string" && ["log", "label"].includes(property)) { // 调用则添加内容 } else { //over logger.addContent(property); return logger.end(); } return self; }, apply(target, thisArg, argumentsList) { const previousProperty = propertyLink[propertyLink.length - 1]; if (previousProperty === "label") { logger.addLabel(...argumentsList); } else if (previousProperty === "log") { logger.addContent(argumentsList); } return self; }, }) as any) as Log; return self; } const Log = new Proxy(getLog(), { get() { return getLog(); }, }); type Log = { error: Log; warn: Log; info: Log; label: (...lables: string[]) => Log; l1: Log; l2: Log; l3: Log; l4: Log; l5: Log; l6: Log; l7: Log; l8: Log; l9: Log; /** 具体消息 */ [k: string]: void | Log | any; log: (...arg: unknown[]) => Log; end: void; }; Log.error.l9.错了呀; Log.error.l9.warn.错了呀; Log.error.l4.那天夕阳下的奔跑是我逝去的青春; Log.warn.l4.log("有毒?").end; Log.warn.l4 .label("登录") .label("游客") .log("失败").end; Log.warn.l4.label("登录", "游客").log("失败").error.密码不对; new Logger() .addLabel("warn", "l4", "登录", "游客", "error") .addContent("失败") .addContent("密码不对") .end();
运行结果