JS中将闭包赋值给变量 无需调用括号即可自增的方案咨询
实现方案
方案1:使用Object.defineProperty定义Getter访问器(最稳定,无类型转换坑)
直接对变量绑定访问器属性,每次读取变量时自动触发getter逻辑执行自增,无需调用括号:
// 封装为IIFE避免counter污染全局作用域 (() => { let counter = 0; Object.defineProperty(window, 'incrementer', { get: () => counter += 5, configurable: false }); })(); // 测试效果 console.log(incrementer); // 5 console.log(incrementer); // 10 console.log(incrementer); // 15
原理:JS读取对象属性时,如果属性定义了get访问器,会自动执行get对应的函数,返回执行结果,不需要额外加调用括号。
方案2:重写函数的valueOf/toString方法
利用JS对函数做类型转换时自动调用valueOf/toString的特性,重写这两个方法实现访问时自增:
const incrementer = (() => { let counter = 0; const inc = () => counter += 5; // 覆盖默认的valueOf和toString方法,所有访问场景都会触发自增 inc.valueOf = inc.toString = inc; return inc; })(); // 测试效果 console.log(incrementer); // 5 console.log(+incrementer); // 10 console.log(incrementer + 0); //15
注意:该方案在强类型判断场景下(比如typeof incrementer)还是会返回function,如果需要完全模拟数值类型,优先选择方案1。
非闭包实现方案
如果不使用闭包存储状态,也可以通过以下方式实现:
基于ES6类私有属性实现
用类的私有属性存储计数器状态,绑定类型转换钩子实现访问自增:
class Incrementer { // ES2022支持的私有属性,外部无法直接修改 #counter = 0; get [Symbol.toPrimitive]() { return () => this.#counter +=5; } toString = () => this.#counter +=5; valueOf = () => this.#counter +=5; } const incrementer = new Incrementer(); // 测试效果 console.log(incrementer); //5 console.log(incrementer); //10
该方案状态完全由类实例维护,不需要依赖闭包的作用域特性,也不会污染全局作用域。
内容的提问来源于stack exchange,提问作者Aly Zidan
相关产品推荐
相关产品推荐

