Javascript Proxy and spread syntax, combined with console.log

Pär*_*son 7 javascript metaprogramming node.js proxy-pattern spread-syntax

So, I was playing around with Proxy objects and while trying to see how they mix with spread syntax and de-structuring, I stubled upon this weird behavior:

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
Run Code Online (Sandbox Code Playgroud)

The above script outputs (on node v10.15.1):

Here comes the unexpected output from console log:

Symbol(nodejs.util.inspect.custom)
Symbol(Symbol.toStringTag)
Symbol(Symbol.iterator)
{ origAttr: undefined, a: undefined, b: undefined }
{ origAttr: 1, a: 1, b: 1 }
Run Code Online (Sandbox Code Playgroud)

Why does console.log(test); output show that the attributes of the object are all undefined? This could cause some serious headache if it were to happen when debugging something.

Is it a bug in node itself or perhaps in the implementation of console.log?

Pär*_*son 2

好吧,我做了一些更多的挖掘,并将整个过程追溯到在我的代理对象上调用 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'))
Run Code Online (Sandbox Code Playgroud)