JavaScript闭包中无需使用eval自动生成getter和setter的实现方法?
自动生成带验证的Getter和Setter解决方案
各位好~我留意到社区里已经有不少关于JavaScript getter和setter的讨论了,大多围绕普通对象展开,少数会涉及闭包场景,但专门讲自动生成带验证逻辑的getter和setter的内容确实不多——而这正是咱们这个问题要聚焦的核心,下面我就分享几个实用的实现方案:
方案1:工厂函数批量生成
这种方式适合给多个属性统一配置getter/setter,还能轻松嵌入自定义验证逻辑:
function createValidatedObject(validations) { const obj = {}; // 遍历验证规则,为每个属性定义getter和setter for (const [prop, validate] of Object.entries(validations)) { let _value; // 用闭包存储私有值 Object.defineProperty(obj, prop, { get() { return _value; }, set(newVal) { if (validate(newVal)) { _value = newVal; } else { throw new Error(`属性${prop}的值无效:${newVal}`); } }, enumerable: true // 让属性可被遍历 }); } return obj; } // 使用示例 const user = createValidatedObject({ age: val => typeof val === 'number' && val >= 0 && val <= 120, name: val => typeof val === 'string' && val.trim().length > 0 }); user.age = 25; // 正常赋值 user.name = ''; // 抛出错误:属性name的值无效:
方案2:ES6类装饰器优雅实现
如果你的项目用了类的写法,装饰器可以帮你给类属性一键添加上带验证的getter/setter,代码更简洁:
// 定义一个验证装饰器 function validated(validateFn) { return function(target, propName) { let _value; Object.defineProperty(target, propName, { get() { return _value; }, set(newVal) { if (validateFn(newVal)) { _value = newVal; } else { throw new Error(`属性${propName}的值无效`); } }, enumerable: true, configurable: true }); }; } // 在类中使用装饰器 class User { @validated(val => typeof val === 'number' && val >= 0) age; @validated(val => typeof val === 'string' && val.trim().length > 0) name; } const user = new User(); user.age = 30; // 正常赋值 user.name = ' '; // 抛出错误:属性name的值无效
方案3:Proxy代理实现全局拦截
如果想要给整个对象的所有属性(包括后续新增的)自动添加getter/setter,Proxy是最灵活的选择:
function createValidatedProxy(obj, validateRule) { return new Proxy(obj, { get(target, prop) { // 这里可以添加自定义的get逻辑,比如日志 console.log(`读取属性${prop}:${target[prop]}`); return target[prop]; }, set(target, prop, newVal) { if (validateRule(prop, newVal)) { target[prop] = newVal; return true; // 表示赋值成功 } else { throw new Error(`属性${prop}的值无效:${newVal}`); } } }); } // 使用示例 const user = createValidatedProxy({}, (prop, val) => { switch(prop) { case 'age': return typeof val === 'number' && val >= 0; case 'name': return typeof val === 'string' && val.trim().length > 0; default: return true; // 其他属性不做验证 } }); user.age = 28; user.name = 'Alice'; user.email = 'alice@example.com'; // 正常通过 user.age = 'twenty'; // 抛出错误:属性age的值无效:twenty
这几个方案各有适用场景:工厂函数适合快速创建带验证的普通对象,装饰器更贴合面向对象的类写法,Proxy则能实现对对象属性的全局动态拦截。你可以根据自己的业务需求来选择~
内容的提问来源于stack exchange,提问作者SumNeuron
相关产品推荐
相关产品推荐

