如何让JS对象数据仅通过对象方法可编辑?
当然可以!原生JavaScript完全能实现这个需求,我给你分享几种实用的方案,你可以根据自己的环境和需求来选:
方案1:利用闭包创建私有变量
闭包可以帮我们把属性藏在函数作用域里,只暴露允许外部调用的方法,这样外部就没法直接修改属性了:
function createPerson() { // 这两个变量是私有状态,只能在函数内部访问 let name = 'alisha'; let country = 'japan'; return { // 如果你需要让外部能读取属性,可以添加getter get name() { return name; }, get country() { return country; }, edit: function(data) { // 只在edit方法里允许修改属性 if (data.name !== undefined) { name = data.name; } if (data.country !== undefined) { country = data.country; } } }; } const a = createPerson(); console.log(a.name); // 输出 'alisha' a.name = 'alisha2'; // 无效,因为没有对应的setter a.edit({ name: 'alisha update' }); console.log(a.name); // 输出 'alisha update'
这个方案兼容性极好,能支持几乎所有旧版浏览器。
方案2:使用Object.defineProperty设置不可写属性
我们可以把对象的name和country属性设置为不可写,这样外部直接赋值会失效,然后在edit方法内部用Object.defineProperty来修改属性值:
var a = (function() { const obj = { edit: function(data) { if (data.name !== undefined) { Object.defineProperty(this, 'name', { value: data.name, writable: false, enumerable: true }); } if (data.country !== undefined) { Object.defineProperty(this, 'country', { value: data.country, writable: false, enumerable: true }); } } }; // 初始化属性为不可写 Object.defineProperty(obj, 'name', { value: 'alisha', writable: false, enumerable: true }); Object.defineProperty(obj, 'country', { value: 'japan', writable: false, enumerable: true }); return obj; })(); console.log(a.name); // 'alisha' a.name = 'alisha2'; // 非严格模式下静默失败,严格模式会抛出错误 a.edit({ name: 'alisha update' }); console.log(a.name); // 'alisha update'
注意:如果把属性的configurable设为false,那edit方法里也没法用Object.defineProperty修改了,所以默认保持configurable: true即可。
方案3:ES6私有字段(推荐现代环境使用)
如果你的运行环境支持ES6及以上,用私有字段是最清晰、最符合现代JS规范的方式:
class Person { // 用#前缀定义私有字段,外部完全无法直接访问 #name = 'alisha'; #country = 'japan'; // 提供getter让外部可以读取属性 get name() { return this.#name; } get country() { return this.#country; } edit(data) { if (data.name !== undefined) { this.#name = data.name; } if (data.country !== undefined) { this.#country = data.country; } } } const a = new Person(); console.log(a.name); // 'alisha' a.#name = 'alisha2'; // 直接抛出语法错误,外部不能访问私有字段 a.edit({ name: 'alisha update' }); console.log(a.name); // 'alisha update'
私有字段会被JS引擎强制保护,外部连访问都做不到,安全性最高。
总结
- 兼容旧环境:选闭包方案
- 现代环境:优先用ES6私有字段
- 想基于原有对象结构改造:用Object.defineProperty方案
内容的提问来源于stack exchange,提问作者Alisha Sharma
相关产品推荐
相关产品推荐

