如何在JavaScript中模拟原始值的引用行为?
解决方案:用Getter/Setter实现原始值的双向绑定
你遇到的核心问题是JavaScript原始类型是按值传递,直接赋值只会创建副本,没法像对象那样通过引用同步更新。你已经用Getter实现了读同步,只需要补充Setter就能完成双向绑定,而且完全不用修改游戏的原始代码。
改进后的实现代码
// 游戏里的混淆变量(假设为全局作用域) let unk = 4; // 定义你的别名,同时配置Getter和Setter Object.defineProperty(globalThis, 'usefulVarName', { get: () => unk, set: (newValue) => { unk = newValue; }, configurable: true // 可选:后续需要修改属性配置时开启 }); // 测试读写同步效果 unk = 5; console.log(usefulVarName); // => 5 (读同步生效) usefulVarName = 6; console.log(unk); // => 6 (写同步生效)
方案原理说明
- Getter:每次访问
usefulVarName时,都会实时返回当前unk的最新值,解决了原始值读同步的问题。 - Setter:每次给
usefulVarName赋值时,都会把新值同步给游戏的原始变量unk,实现了双向写同步。 - 完全不侵入游戏代码:游戏对
unk的使用逻辑不需要任何修改,你的扩展只需要维护这个别名的定义即可。
非全局作用域的处理方式
如果unk不是全局变量,而是存在于游戏的局部作用域中,你需要确保Getter/Setter能访问到该作用域,可通过闭包保存作用域引用:
// 假设你能通过调试、AST分析等方式获取到unk所在的作用域对象 function setupAlias(scope) { Object.defineProperty(globalThis, 'usefulVarName', { get: () => scope.unk, set: (val) => { scope.unk = val; } }); } // 调用时传入包含unk的作用域 setupAlias({ unk: 4 });
关于Proxy的补充说明
Proxy主要用于代理对象的行为,对于单个原始值来说,确实不如Getter/Setter直接高效。除非你把原始值包装成对象,但这需要修改游戏中对unk的所有引用,而你无法控制游戏代码,因此该方案不适用。
额外优化建议
每次游戏更新后,你只需要找到新的混淆变量名(比如原来的unk变成了xyz),修改Getter/Setter里的变量名即可,扩展的业务代码完全不需要改动,完美实现了「只改引用、不改业务代码」的需求。
内容的提问来源于stack exchange,提问作者Ufodynasty
相关产品推荐
相关产品推荐

