Javascript代理和传播语法,与console.log相结合

时间:2019-03-11 16:15:30

标签: javascript node.js metaprogramming spread-syntax proxy-pattern

因此,我在研究代理对象,并尝试查看它们如何与扩展语法和解构结构混合使用时,我对这种奇怪的行为感到固执:

const obj = {
  origAttr: 'hi'
}

const handler = {
  get(target, prop) {
    console.log(prop);
    return 1;
  },
  has(target, prop) {
    return true;
  },
  ownKeys(target) {
    return [...Reflect.ownKeys(target), 'a', 'b'];
  },
  getOwnPropertyDescriptor(target, key) {
    return {
      enumerable: true,
      configurable: true
    };
  }
}

const test = new Proxy(obj, handler);
const testSpread = { ...test};

console.log('Iterate test');
// Works OK, output as expected
for (const i in test) {
  console.log(i, ' -> ', test[i]);
}

console.log('Iterate testSpread');
// Also works OK, output as expected
for (const i in testSpread) {
  console.log(i, ' -> ', testSpread[i]);
}

console.log('Here comes the unexpected output from console.log:');
console.log(test); // All attributes are 'undefined'
console.log(testSpread); // This is OK for some wierd reason

以上脚本输出(在节点v10.15.1上):

这是控制台日志中的意外输出:

Symbol(nodejs.util.inspect.custom)
Symbol(Symbol.toStringTag)
Symbol(Symbol.iterator)
{ origAttr: undefined, a: undefined, b: undefined }
{ origAttr: 1, a: 1, b: 1 }

为什么console.log(test);输出表明对象的属性全部未定义?如果在调试某些内容时发生这种情况,可能会引起一些严重的头痛。

是节点本身还是在console.log的实现中存在错误?

1 个答案:

答案 0 :(得分:3)

好的,我做了一些进一步的挖掘,并将整个过程追溯到在代理对象上调用Object.getOwnPropertyDescriptor以获得其属性值。

但是在我的情况下,“ value”属性显然是未定义的,因为我有一个getOwnPropertyDescriptor陷阱,该陷阱仅指定可枚举和可配置的属性(因此可以迭代数组,将其与散布运算符结合使用,依此类推) 。 由于没有从getOwnPropertyDescriptor陷阱中调用get陷阱的标准方法,因此恕我直言,这不是固定的。有趣的是被证明是错误的:)

好吧,正如Bergi在评论中指出的那样,这是一种标准方法。

还在文档https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor#Parameters中“这绑定到处理程序”

编辑我的代码以反映这一点。

展示getOwnPropertyDescriptor行为的代码如下:

const obj = {
  origAttr: 'hi'
}

const handler = {
  get(target, prop) {
    return 1;
  },
  has(target, prop) {
    return true;
  },
  ownKeys(target) {
    return [...Reflect.ownKeys(target), 'a', 'b'];
  },
  getOwnPropertyDescriptor(target, key) {
    return {
      value: this.get(target, key),
      enumerable: true,
      configurable: true
    };
  }
}

const test = new Proxy(obj, handler);
const testSpread = { ...test
};

// Defined, due to trapped getOwnPropertyDescriptor which returns a value attribute
console.log(Object.getOwnPropertyDescriptor(test, 'origAttr'))

// Defined, because it is a regular object, not a proxy with a getOwnPropertyDescriptor trap
console.log(Object.getOwnPropertyDescriptor(testSpread, 'origAttr'))