Прокси Javascript и распространенный синтаксис в сочетании с console.log - PullRequest
7 голосов
/ 11 марта 2019

Итак, я играл с прокси-объектами и, пытаясь понять, как они сочетаются с распространенным синтаксисом и деструктуризацией, я наткнулся на это странное поведение:

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 (тест); вывод показывает, что атрибуты объекта все неопределены? Это может вызвать серьезную головную боль, если это произойдет при отладке чего-либо.

Это ошибка в самом узле или, возможно, в реализации console.log?

Ответы [ 2 ]

2 голосов
/ 12 марта 2019

Хорошо, я сделал еще несколько копаний и отследил все это до Object.getOwnPropertyDescriptor, вызываемого на моем прокси-объекте, чтобы получить значения его атрибутов.

Но атрибут "value" явно не определен вВ моем случае, поскольку у меня есть ловушка для getOwnPropertyDescriptor, которая задает только перечислимые и настраиваемые атрибуты (таким образом, делая возможным итерацию массива, использование его с операторами распространения и т. д.). Поскольку не существует стандартного способа вызова ловушки get из ловушки getOwnPropertyDescriptor, это не может быть исправлено IMHO.Хотя было бы интересно доказать, что это неправильно:)

Ну, как отметил Берги в комментариях, есть стандартный способ.

Также в документах 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'))
0 голосов
/ 11 марта 2019

объект Proxy, согласно определению Proxy - это не что иное, как виртуализация объекта, с которым вы его используете.

Следовательно, сам объект Proxy имеет только атрибуты объекта, которым вы являетесьпроксирование, если вы попытаетесь запустить console.log(test), вы увидите, что консоль выведет Proxy {origAttr: "hi"}, но у нее также будет обработчик и цель внутри, которые вы определили выше.

Когда вы вместо этого используете оператор распространениявы создаете новый объект, который создается так же, как если бы вы итерировали свойства вашего Proxy объекта следующим образом:

Object.keys(test) --> ["origAttr", "a", "b"], потому что это то, что вы определили в ownKeys(target) { return [...Reflect.ownKeys(target), 'a', 'b']; }.

Затем он получит доступ к test["origAttr"], затем test["a"] и test["b"], используя функцию прокси get, которая всегда возвращает 1.

В результате вы на самом деле возражаете testSpreadсодержит эти атрибуты, а test нет.

А при запуске console.log(testSpread) --> {origAttr: 1, a: 1, b: 1}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...