djf*_*dev 1 javascript ecmascript-6 redux
我是 ES6 对象的新手,在尝试调用已代理的数组Proxy时遇到了我不明白的错误。concat
背景:
\n\n我认为 ES6Proxy可以完美地作为一种方式来验证我的 React/Redux 应用程序中的减速器函数的“纯度”。我可以将我的状态对象包装在代理中,如果我尝试改变该对象,该代理会抛出错误。我正在使用基于on-change库的东西来执行此操作:
const triggersOnChange = (object, onChange) => {\n const handler = {\n get (target, property, receiver) {\n try {\n return new Proxy(target[property], handler)\n } catch (err) {\n return Reflect.get(target, property, receiver);\n }\n }\n\n defineProperty (target, property, descriptor) {\n onChange()\n return Reflect.defineProperty(target, property, descriptor)\n }\n\n deleteProperty (target, property) {\n onChange()\n return Reflect.deleteProperty(target, property)\n }\n }\n\n return new Proxy(object, handler)\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这是我打算如何使用代理包装器的示例测试:
\n\ndescribe(\'reducer\', () => {\n test(\'it returns an updated state object\', () => {\n const state = triggersOnChange({ items: [] }, () => {\n throw new Error(\'Oops! You mutated the state object\')\n })\n\n const action = {\n payload: { item: \'foobar\' }\n }\n\n expect(reducer(state, action)).toEqual({\n items: [action.payload.item]\n })\n })\n})\nRun Code Online (Sandbox Code Playgroud)\n\n如果我实现了一个改变状态对象的“坏”减速器,我的测试会按预期抛出错误:
\n\nconst reducer = (state, action) => {\n state.items.push(action.payload.item) // bad\n return state\n}\n\n// test throws error "Oops! You mutated the state object"\nRun Code Online (Sandbox Code Playgroud)\n\n但是当我通过返回一个新的状态对象来“净化”我的减速器时,我得到了一个我不太理解的不同错误:
\n\nconst reducer = (state, action) => {\n return Object.assign({}, state, {\n items: state.items.concat(action.payload.item)\n })\n}\n\n/* \n TypeError: \'get\' on proxy: property \'prototype\' is a read-only and\n non-configurable data property on the proxy target but the proxy did\n not return its actual value (expected \'[object Array]\' but got\n \'[object Object]\')\n at Proxy.concat (<anonymous>)\n*/\nRun Code Online (Sandbox Code Playgroud)\n\n我在这里遗漏了一些有关代理行为的信息吗?或者这可能是我的陷阱导致的代理链接行为的问题get?我最初认为这是在 中使用代理的问题Object.assign,但是在我实际使用的减速器的 return 语句之前进行调试时,我遇到了同样的错误Object.assign。帮助!
编辑:很高兴修改这个问题以使其更通用,但我\xe2\x80\x99m 不是 100% 问题是什么,所以我\xe2\x80\x99ll 等待,看看是否能得到任何答案。
\n可以使用以下代码复制您的问题:
var obj = {};
Object.defineProperty(obj, "prop", {
configurable: false,
value: {},
});
var p = new Proxy(obj, {
get(target, property, receiver) {
return new Proxy(Reflect.get(target, property, receiver), {});
},
});
var val = p.prop;
Run Code Online (Sandbox Code Playgroud)
问题的核心是对象具有必须保持一致的不变量,即使是通过代理对象访问时也是如此,在这种情况下,您将破坏这些不变量之一。如果您查看Proxy's 的规范get,它会指出:
代理对象的 [[Get]] 强制执行以下不变量:
- 如果目标对象属性是不可写、不可配置的自有数据属性,则为属性报告的值必须与相应目标对象属性的值相同。
- 如果相应的目标对象属性是其 [[Get]] 属性未定义的不可配置的自身访问器属性,则为属性报告的值必须为未定义。
在您的情况下,您不会维护第一个不变式,因为即使属性不可写且不可配置,您也会返回一个包装代理。最简单的方法是确保在这种情况下返回正确的值。
当我们这样做时,我还建议typeof显式使用而不是使用try/ catch,这样会更清晰。
get(target, property, receiver) {
const desc = Object.getOwnPropertyDescriptor(target, property);
const value = Reflect.get(target, property, receiver);
if (desc && !desc.writable && !desc.configurable) return value;
if (typeof value === "object" && value !== null) return new Proxy(value, handler);
else return value;
},
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
953 次 |
| 最近记录: |