可用 Proxy 拦截属性读取并在属性不存在时抛出带对象名、属性名及建议键名的自定义错误;基础版用 prop in target 判断,进阶版支持嵌套代理与自有属性精确检查,并缓存已代理对象。

可以用 Proxy 拦截对象的属性读取(get),在目标属性不存在时抛出带上下文信息的自定义错误,而不是默认的 undefined 或静默失败。
核心思路:拦截 get 并检查属性是否存在
通过 Reflect.get(target, prop, receiver) 获取原始值,再结合 prop in target 或 Object.prototype.hasOwnProperty.call(target, prop) 判断属性是否真实存在。若不存在,就抛出带对象名、属性名和建议提示的错误。
基础实现:简单友好的未定义属性警告
以下是一个可复用的包装函数:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
function createSafeProxy(obj, objName = 'object') {
return new Proxy(obj, {
get(target, prop) {
if (prop in target) {
return Reflect.get(target, prop);
}
throw new Error(`⚠️ ${objName} has no property '${String(prop)}'. Did you mean one of: ${Object.keys(target).join(', ') || 'none'}?`);
}
});
}
// 使用示例
const user = createSafeProxy({ name: 'Alice', age: 30 }, 'user');
console.log(user.name); // 'Alice'
console.log(user.email); // 抛出:⚠️ user has no property 'email'. Did you mean one of: name, age?
进阶优化:支持嵌套对象与原型链判断
如果对象有原型或需区分自有属性与继承属性,可用 Object.prototype.hasOwnProperty.call(target, prop) 精确判断“自有属性”;对嵌套访问(如 user.profile.city),需确保每一层都用 createSafeProxy 包裹,或在 get 中递归代理返回值:
- 对返回的对象值自动包装为新 Proxy(避免手动包裹每层)
- 跳过 Symbol、函数、null/undefined 等非对象值,不代理
- 缓存已代理的对象,避免重复创建 Proxy
function createSmartProxy(obj, objName = 'object', seen = new WeakMap()) {
if (!obj || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
const proxy = new Proxy(obj, {
get(target, prop) {
if (Object.prototype.hasOwnProperty.call(target, prop)) {
const val = Reflect.get(target, prop);
// 对普通对象自动代理,跳过函数、Date、RegExp 等
if (val && typeof val === 'object' && !val.constructor?.name.match(/^(Function|Date|RegExp|Promise|Window|global|Array)$/)) {
const nestedProxy = createSmartProxy(val, `${objName}.${String(prop)}`, seen);
seen.set(val, nestedProxy);
return nestedProxy;
}
return val;
}
throw new Error(`❌ Property '${String(prop)}' not found on ${objName}. Available keys: ${Object.keys(target).length ? Object.keys(target).join(', ') : '(none)'}`);
}
});
seen.set(obj, proxy);
return proxy;
}
实际使用注意点
- Proxy 只拦截对象本身,不改变原型链行为;若需拦截原型属性,需代理原型对象或改用
getPrototypeOf拦截 - 数组索引访问(
arr[0])、length、数组方法(push)等均受get拦截,需按需放行或增强提示 - 避免在
get中执行耗时逻辑(如网络请求),否则会影响所有属性读取性能 - 开发环境启用,生产环境可关闭以减少开销(用条件编译或环境变量控制)
不复杂但容易忽略的是:友好提示的价值不在技术难度,而在第一时间帮开发者定位拼写错误、API 变更或文档滞后问题。

















