如何使用javascript代理嵌套对象

Afl*_*red 36 javascript proxy ecmascript-6 es6-proxy

我在js bin中有这个代码:

var validator = {
  set (target, key, value) {
    console.log(target);
    console.log(key);
    console.log(value);
    if(isObject(target[key])){

    }
    return true
  }
}


var person = {
      firstName: "alfred",
      lastName: "john",
      inner: {
        salary: 8250,
        Proffesion: ".NET Developer"
      }
}
var proxy = new Proxy(person, validator)
proxy.inner.salary = 'foo'
Run Code Online (Sandbox Code Playgroud)

如果我这样做proxy.inner.salary = 555;不起作用.

但是,如果我这样做proxy.firstName = "Anne",那么它的效果很好.

我不明白为什么它不起作用递归.

http://jsbin.com/dinerotiwe/edit?html,js,console

Mic*_*ski 34

您可以添加get陷阱并返回一个新的代理validator作为处理程序:

var validator = {
  get(target, key) {
    if (typeof target[key] === 'object' && target[key] !== null) {
      return new Proxy(target[key], validator)
    } else {
      return target[key];
    }
  },
  set (target, key, value) {
    console.log(target);
    console.log(key);
    console.log(value);
    return true
  }
}


var person = {
      firstName: "alfred",
      lastName: "john",
      inner: {
        salary: 8250,
        Proffesion: ".NET Developer"
      }
}
var proxy = new Proxy(person, validator)
proxy.inner.salary = 'foo'
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。但这样每次都会返回一个新的 Proxy 实例。如果创建了相同的 Proxy 实例,是否会返回该实例? (3认同)
  • @robertking Array也是一个对象,因此它是一个对象内部的对象,这个代码应该与深层嵌套的对象一起使用. (2认同)

Jam*_*yle 17

Micha的示例稍作修改Per?akowski与这种方法的好处是嵌套代理只创建一次,而不是每次访问一个值。

如果正在访问的代理的属性是一个对象或数组,则该属性的值将替换为另一个代理。isProxygetter 中的属性用于检测当前访问的对象是否为代理。您可能希望更改 的名称isProxy以避免与存储对象的属性发生命名冲突。

注意:嵌套代理是在 getter 而不是 setter 中定义的,因此只有在数据实际在某处使用时才会创建它。这可能适合也可能不适合您的用例。

const handler = {
  get(target, key) {
    if (key == 'isProxy')
      return true;

    const prop = target[key];

    // return if property not found
    if (typeof prop == 'undefined')
      return;

    // set value as proxy if object
    if (!prop.isProxy && typeof prop === 'object')
      target[key] = new Proxy(prop, handler);

    return target[key];
  },
  set(target, key, value) {
    console.log('Setting', target, `.${key} to equal`, value);

    // todo : call callback

    target[key] = value;
    return true;
  }
};

const test = {
  string: "data",
  number: 231321,
  object: {
    string: "data",
    number: 32434
  },
  array: [
    1, 2, 3, 4, 5
  ],
};

const proxy = new Proxy(test, handler);

console.log(proxy);
console.log(proxy.string); // "data"

proxy.string = "Hello";

console.log(proxy.string); // "Hello"

console.log(proxy.object); // { "string": "data", "number": 32434 }

proxy.object.string = "World";

console.log(proxy.object.string); // "World"
Run Code Online (Sandbox Code Playgroud)

  • 我相信 .isBindingProxy 应该是 ,isProxy ? (3认同)
  • 如果您使用的是 Node v10+,您还可以使用 [util.types.isProxy](https://nodejs.org/api/util.html#util_util_types_isproxy_value) 而不是手动“设置”isProxy (3认同)
  • 对于浏览器方法,建议:声明:`const isProxy = Symbol("isProxy")`。然后使用 `key === isProxy` 代替。 (3认同)

Ell*_* B. 9

在GitHub上发布了一个库,它也是这样做的.它还将向回调函数报告已完成的修改及其完整路径.

Michal的答案很好,但Proxy 每次访问嵌套对象时都会创建一个新的.根据您的使用情况,这可能会导致非常大的内存开销.

  • @KilianHertel 看一下 Michal 答案中的第一个“if”语句。如果访问的属性是一个非空的“对象”,它会创建一个新的“代理”。因此,当然,根据您的使用情况,创建一堆新的 Proxy 对象很可能会导致内存使用量增加。您的里程将根据垃圾收集情况而有所不同。詹姆斯提供的另一个答案也解决了这个问题。为什么我的回答会给米哈尔的回答“带来坏名声”?我说他的回答很好,我自己也投了赞成票...... (2认同)