Proxy 可拦截对象读写操作,通过 get/set 陷阱实现蛇形与驼峰命名自动转换:内部统一存蛇形(如 user_name),对外暴露驼峰接口(如 userName);借助 toSnake/toCamel 工具函数动态映射,支持双向兼容与深层代理扩展。

Proxy 可以拦截对象的读写操作,在 get 和 set 陷阱中动态处理属性名,实现蛇形命名(user_name)与驼峰命名(userName)的自动转换。关键在于统一内部存储用蛇形,对外暴露驼峰接口,或反之。
核心思路:统一内部命名规范 + 动态映射
推荐将原始数据(如后端返回的蛇形字段)存为私有属性(如 _data),再通过 Proxy 的 get/set 拦截,把用户访问的驼峰名自动转为蛇形去操作真实数据。这样既保持外部使用习惯,又不侵入原始数据结构。
例如:obj.userName 实际读取的是 _data.user_name;obj.userId 对应 _data.user_id。
工具函数:驼峰 ⇄ 蛇形互转
先封装两个轻量转换函数,用于在 Proxy 中复用:
立即学习“Java免费学习笔记(深入)”;
(可直接复制使用)
// 驼峰转蛇形(支持连续大写如 XMLHttp → xml_http)
function toSnake(str) {
return str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
}
// 蛇形转驼峰(忽略非字母数字下划线,首字母小写)
function toCamel(str) {
return str.replace(/_([a-z])/g, (m, p1) => p1.toUpperCase());
}
创建代理:自动转换读写属性名
以下是一个完整可运行示例,代理一个蛇形数据对象,使其支持驼峰访问:
function createCamelProxy(data) {
const handler = {
get(target, prop) {
if (typeof prop === 'string' && !prop.startsWith('_')) {
const snake = toSnake(prop);
return target[snake];
}
return target[prop];
},
set(target, prop, value) {
if (typeof prop === 'string' && !prop.startsWith('_')) {
const snake = toSnake(prop);
target[snake] = value;
return true;
}
target[prop] = value;
return true;
},
has(target, prop) {
if (typeof prop === 'string' && !prop.startsWith('_')) {
return prop in target || toSnake(prop) in target;
}
return prop in target;
}
};
return new Proxy(data, handler);
}
// 使用示例
const raw = { user_name: 'Alice', user_age: 28, is_active: true };
const user = createCamelProxy(raw);
console.log(user.userName); // 'Alice'
console.log(user.userAge); // 28
console.log(user.isActive); // true
user.userId = 1001; // 写入 raw.user_id = 1001
console.log(raw.user_id); // 1001
进阶:双向兼容 + 原始属性保留
如果希望同时支持蛇形和驼峰访问(比如兼容旧代码),可在 get/set 中优先尝试驼峰转蛇形,失败再直接查原名:
- 在
get中:先查toSnake(prop),不存在则查prop本身 - 在
set中:若prop已是蛇形(含下划线),直接赋值;否则转蛇形再赋值 - 用
Reflect.ownKeys或Object.keys获取所有键时,建议返回驼峰形式(需额外缓存映射或遍历生成)
注意:Proxy 不会自动代理嵌套对象,如需深层转换,需在 get 返回值为对象时递归 wrap —— 可封装为 deepCamelProxy。


















