4

我有一个 ES6 代理,其中包含其他深度嵌套的代理(在根代理的 get 陷阱中生成)。它们都使用相同的陷阱处理程序。

当我尝试获取此集合中深层嵌套对象的值时,会为遇到的每个深层嵌套对象调用 getter。在获取序列完成后,必须知道通过对象的所谓“路径”的记录。例如,调用:

console.log(proxy.shallow.deep);

是两个 get 操作的“链”,shallowdeep顺序排列,这两个操作都被推送到一个数组,充当链中访问的属性的面包屑路径,例如:

console.log(path); // ['shallow', 'deep']

不过,这有一个问题。在任何获取序列中,都不可能知道链中的最终获取是什么 - 对代理的每次获取都被视为原子操作,因此没有关于最后被调用的属性的内在概念。这意味着在随后的“获取链”中,path数组已经有与之关联的值。我在下面编写了一些代码来说明我的代理的结构和我遇到的问题:

let nestedObject = { shallow: { deep: 0 }};
let path = [];
let proxy = new Proxy(nestedObject, {
    get(target, prop) {
        path.push(prop);
        let out = target[prop];
        // this ensures each get to the proxy (whenever the value at property 
        // is an object), returns that object as a new proxy, 
        // else return the value of the property
        // this means the get/set traps are called for each deeply nested object
        return typeof out === 'object' ? new Proxy(out, this) : out;
    },
    set(target, prop, val) {
        path.push(prop);
        target[prop] = val;
        path.length = 0;
    }
});

// getting these two pushes both properties to the path array
// but there's no way of knowing that the get to 'deep' was the final 
// get in the chain - therefore it cannot be reset for the next get chain
proxy.shallow.deep;
// path: ['shallow', 'deep']
console.log(path);

// because of this, I can't figure out how the code should know that the path
// array must be reset - so subsequent gets just add more values to the path array,
// and there are erroneous elements in the array when the next chain starts
proxy.shallow.deep
// path: ['shallow', 'deep', 'shallow', 'deep']
console.log(path);

// setting a value is fine however, since a set action will always be the last action
// it pushes 'shallow' to the array in the getter and 'deep' in setter. 
// The setter can then clear the path array.
proxy.shallow.deep = 1;
// path: []
console.log(path);

所以我想知道的是:是否有可能以某种方式知道链中的最后一个“获取”是什么,和/或是否有办法在获取链完成时调用函数?

谢谢您的帮助!

4

1 回答 1

1

我想我已经为我找到了一个合理的解决方案,它只需要对代码进行很少的更改。它涉及将路径变量附加到每个连续的陷阱处理程序,其值是每个先前处理程序的路径值的累积值。像这样:

let nestedObject = { shallow: { deep: {deepest: 0 }}};
let path = [];
let proxy = new Proxy(nestedObject, {
    get(target, prop) {
        let out = target[prop];
        // make a copy of this handler for the nested proxy to use
        let copy = Object.assign({}, this);
        // if this handler contains no path variable, add it
        // otherwise concatenate it with the previous handler's path 
        !this.path ?
            Object.assign(copy, {path: [prop]}) :
            Object.assign(copy, {path: this.path.concat(prop)});
        path = copy.path;
        return typeof out === 'object' ?
            new Proxy(out, copy) :
            out;
    },
    set(target, prop, val) {
        path = this.path.concat(prop);
        target[prop] = val;
    }
});

proxy.shallow;
console.log(path); // ['shallow']
proxy.shallow.deep;
console.log(path); // ['shallow', 'deep']
proxy.shallow.deep.deepest;
console.log(path); // ['shallow', 'deep', 'deepest']
proxy.shallow.deep.deepest = 1;
console.log(path); // ['shallow', 'deep', 'deepest']

我不确定这是否是最佳解决方案,但它确实有效。虽然我仍然很想看到实现这一点的任何替代方法。

谢谢你们的帮助。

于 2018-02-12T21:34:30.633 回答