JavaScript中如何防止通过get方法修改构造函数内的状态对象
问题原因
getState直接返回了内部私有对象SecretState的引用,JavaScript里对象属于引用类型,外部拿到这个引用后可以直接修改对象属性,完全绕过setState的逻辑,所以执行m.getState().name = 'Alice'时会直接改动内部存储的真实状态,最终输出不符合预期。
可行实现方案
- 方案1:返回状态副本(通用首选)
不直接返回原对象引用,而是返回状态的拷贝,外部修改拷贝对象不会影响内部真实状态。
单层简单状态用浅拷贝即可,性能开销极低:
如果状态存在多层嵌套结构,用原生function State(){ const SecretState = { name: 'bob' } // 浅拷贝后返回 this.getState = () => ({ ...SecretState }); this.setState = (name) => SecretState.name = name; } const m = new State() m.setState('Smith') m.getState().name = 'Alice' // 修改的是临时生成的拷贝对象,不影响内部状态 console.log(m.getState().name) // 输出 SmithstructuredClone做深拷贝即可,避免嵌套属性被篡改:this.getState = () => structuredClone(SecretState); - 方案2:直接返回属性原始值
如果不需要一次性获取整个状态对象,直接返回目标属性的原始值即可。原始类型是值传递,外部拿到值后的修改操作和内部状态完全无关:function State(){ const SecretState = { name: 'bob' } this.getName = () => SecretState.name; this.setName = (name) => SecretState.name = name; } const m = new State() m.setName('Smith') const currentName = m.getName() // 这里修改的是独立的字符串原始值,不会改动内部状态 currentName + '123' console.log(m.getName()) // 输出 Smith - 方案3:返回只读代理(适合大体积状态场景)
如果状态对象体积很大,每次全量拷贝的性能开销过高,可以返回原对象的只读Proxy代理,拦截所有外部修改操作,既不会改动原对象,也没有拷贝开销:function State(){ const SecretState = { name: 'bob' } const readonlyHandler = { set() { console.warn('禁止直接修改状态,请使用setState方法更新') return false }, get(target, prop) { const val = target[prop] // 嵌套对象也递归生成只读代理 return typeof val === 'object' && val !== null ? new Proxy(val, readonlyHandler) : val } } const readOnlyState = new Proxy(SecretState, readonlyHandler) this.getState = () => readOnlyState; this.setState = (name) => SecretState.name = name; } const m = new State() m.setState('Smith') m.getState().name = 'Alice' // 触发警告,修改不生效 console.log(m.getState().name) // 输出 Smith
内容的提问来源于stack exchange,提问作者relidon
相关产品推荐
相关产品推荐

