JavaScript代理'get' TypeError错误含义解析及相关疑问解答
你是不是看到这个错误一脸困惑?明明返回的和预期都是数组,为啥JS还揪着不放?而且代理不就是用来改返回值的吗?别着急,咱们一步步拆解这个问题:
错误信息的核心含义
先把这条错误拆成两部分看:
TypeError: 'get' on proxy: property 'items' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '[object Array]' but got '[object Array]')
- 前半段:明确告诉你目标对象上的
items属性是个被完全锁死的属性——它通过Object.defineProperty或类似方式设置了writable: false(只读,不能直接修改值)和configurable: false(不可配置,不能修改属性描述符、不能删除属性)。 - 后半段:你的代理
get陷阱返回的不是这个属性的原始值,哪怕看起来都是数组,但JS判定两者不是同一个东西(因为是不同的引用)。
为什么代理不能随便改这个返回值?
这是ES规范给Proxy的get陷阱定的硬规则:
如果目标属性是不可配置且只读的数据属性,那么
get陷阱的返回值必须和目标属性的原始值严格相等(===)。
为啥要搞这个规则?因为这类属性是开发者明确“锁死”的,意味着这个属性的取值是固定、不可篡改的。如果代理能随便返回别的值,就破坏了原本的属性契约——毕竟你都把属性设成只读不可配置了,就是不想让它变,代理要是偷偷改了,就违背了这个设计意图。
举个实际例子一看就懂:
// 先创建一个带锁死属性的目标对象 const target = {}; Object.defineProperty(target, 'items', { value: [], // 原始数组 writable: false, configurable: false }); // 错误的代理:返回了一个新的空数组 const badProxy = new Proxy(target, { get(target, prop) { if (prop === 'items') return []; // 这里返回的是新数组,和原始引用不一样 return Reflect.get(...arguments); } }); console.log(badProxy.items); // 直接触发你看到的那个错误! // 正确的代理:返回原始值的引用 const goodProxy = new Proxy(target, { get(target, prop) { if (prop === 'items') return target.items; // 返回原始数组的引用,和目标值严格相等 return Reflect.get(...arguments); } }); console.log(goodProxy.items); // 正常输出,不会报错
为啥类型一致还报错?
你注意到错误里说“expected '[object Array]' but got '[object Array]'”,这是因为JS里引用类型的相等是引用相等,不是值相等。你返回的新数组[]和目标上的原始数组[]是两个完全不同的对象,哪怕它们的类型、内容都一样,===比较的结果也是false。JS就是因为这个,判定你返回的不是“实际值”,所以报错。
总结一下
这个错误的本质是:你违反了Proxy的规范约束——对于不可配置且只读的目标属性,get陷阱必须返回属性的原始值(严格相等),不能返回任何替代值,哪怕替代值看起来和原始值一模一样。
内容的提问来源于stack exchange,提问作者Fabis

