Индекс прокси преобразуется в строку

Пробуя новые прокси-объекты, я был удивлен, что при установке прокси ключ автоматически преобразуется в строку:

var arr = ['a', 'b', 'c'];

arr = new Proxy(arr, {
  get: (original, key) => {
    alert(typeof key);
    return original[key];
  }
});

arr[1];  // expected an alert with 'number'; got 'string' instead

Там я ожидал бы, что typeof key будет number, так как я передаю ему число. Однако он каким-то образом преобразуется в строку внутри Proxy, а фактический предупреждаемый тип — string. Вы можете увидеть здесь небольшой JSFiddle, демонстрирующий проблему. arr по-прежнему является массивом даже после его передачи через прокси.

Итак, как я могу отличить передачу строки от числа? Я мог бы просто использовать регулярное выражение, как в /\d+/.test(key), однако это не отличало бы эти ситуации, и это просто похоже на хак:

arr['1'];
arr[1];

person Francisco Presencia    schedule 05.10.2016    source источник
comment
Имя свойства преобразуется в строку еще до того, как будет определено значение доступа к свойству, т. е. проксируемый объект не может узнать исходное значение. См. спецификацию: ecma-international .org/ecma-262/7.0/   -  person Felix Kling    schedule 05.10.2016
comment
По совпадению, собственный массив также не будет различать arr['1'] и arr[1] по причине, которая объясняется в ответе. Так что да, /^\d+$/ следует использовать. Пример см. на stackoverflow.com/a/39802685/3731501.   -  person Estus Flask    schedule 05.10.2016


Ответы (1)


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

arr['1'];
arr[1];

Оба они вызовут обработчик получения прокси с '1' в качестве ключа свойства.


Кроме того, тот факт, что вы используете массив, ничего не меняет — он работает с массивами (которые представляют собой объекты особого типа) так же, как и с обычными объектами.


См. также Тип объекта в спецификации.

person Michał Perłakowski    schedule 05.10.2016
comment
Отлично спасибо. В вашем первом предложении я также нашел более актуальную информацию: stackoverflow.com/questions/2940424/ (и ссылка на MDN: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/ ). Таким образом, в основном это доступ к самому массиву, который преобразует его в строку, ничего общего с прокси. - person Francisco Presencia; 05.10.2016
comment
Стоит отметить, что я решил это с помощью простого if (key in lists) return lists[key];, который поймает как общие методы массива, такие как .forEach(), .map() и т. д., так и указанные числовые индексы. - person Francisco Presencia; 05.10.2016