После некоторых исследований по этой проблемы, оказалось, что на самом деле есть способ безумия.
Это не было сразу очевидно из моего тестирования, но весьма полезно понять примеры, которые сработали.
console.log(source[srcKeys]);
console.log(source[[[[srcKeys]]]]);
console.log(source[[],[[[srcKeys]]]]);
console.log(source[[],[[srcKeys]]]);
console.log(source[[[]],[],srcKeys]);
console.log(source[[[]],[[srcKeys]]]);
Вы заметите, что на самом деле существует шаблон, который изначально не был очевиден в этих утверждениях.
Каждое средство доступа к свойству является либо выражением с запятой (которое будет оцениваться как последнее значение в выражении — обычно это массив), либо просто массивом.
console.log(source[srcKeys]); // => array
console.log(source[[[[srcKeys]]]]); // => array
console.log(source[[],[[[srcKeys]]]]); // => comma expression
console.log(source[[],[[srcKeys]]]); // => comma expression
console.log(source[[[]],[],srcKeys]); // => comma expression
console.log(source[[[]],[[srcKeys]]]); // => comma expression
Более того, каждый массив представляет собой либо массив из одного элемента, либо вложенный массив массивов из одного элемента.
Вооружившись этими знаниями, пришло время попытаться понять, как спецификация ECMAScript излагает оценку property accessors
.
.
Я избавлю вас от кровавых подробностей и вместо этого дам краткое изложение того, что происходит почти в 99% случаев:
Выражение свойства сначала преобразуется в строку (если это не символ начиная с es6), затем возвращается ссылка на значение, которое имеет данное имя свойства
Итак, теперь мы понимаем, что JavaScript просто попытается преобразовать любое средство доступа к свойству в строку и использовать эту строку в качестве имени свойства.
Кроме того, массивы имеют интересное поведение при преобразовании в строку. Вы можете прочитать этот другой ответ, чтобы получить более полное представление о том, как массив преобразуется в имя свойства.
Не очень секретное открытие
Давайте теперь применим все, что мы знаем, к приведенным примерам и посмотрим, почему некоторые из них сработали, а некоторые нет.
Сначала рассмотрим примеры, которые не сработали:
console.log(source[[[],[[srcKeys]]]]); // => property accessor expression is [[],[[srcKeys]]]
console.log(source[[[],[],[[srcKeys]]]]); // => property accessor expression is [[],[],[[srcKeys]]]
console.log(source[[[[]],[[srcKeys]]]]); // => property accessor expression is [[[]],[[srcKeys]]]
Одной неизменной деталью каждого из этих выражений является то, что все они являются массивами из нескольких элементов. Быстро становится очевидным, почему они не дали нам ожидаемого значения, а предыдущие дали. Для этого я сейчас покажу результат toString
для всех массивов.
const source = {
last: "Capulet"
};
const srcKeys = Object.keys(source);
// console.log(source[srcKeys]);
console.log(srcKeys.toString());
// console.log(source[[[[srcKeys]]]]);
console.log([
[
[srcKeys]
]
].toString());
// console.log(source[[],[[[srcKeys]]]]);
console.log(([], [
[
[srcKeys]
]
]).toString());
// console.log(source[[],[[srcKeys]]]);
console.log(([], [
[srcKeys]
]).toString());
// console.log(source[[[]],[],srcKeys]);
console.log(([
[]
], [], srcKeys).toString());
// console.log(source[[[]],[[srcKeys]]]);
console.log(([
[]
], [
[srcKeys]
]).toString());
// console.log(source[[[],[[srcKeys]]]]);
console.log([
[],
[
[srcKeys]
]
].toString());
// console.log(source[[[],[],[[srcKeys]]]]);
console.log([
[],
[],
[
[srcKeys]
]
].toString());
// console.log(source[[[[]],[[srcKeys]]]]);
console.log([
[
[]
],
[
[srcKeys]
]
].toString());
И вот оно. Первые сработавшие примеры имеют значение toString last
, а остальные нет.
Сначала я подумал, что сглаживание вложенных массивов — интересное поведение. Я ожидал, что преобразование массива в строку:
[[],[[srcKeys]]]
выведет:[,[srcKeys]]
, НО затем я понял, что массив преобразуется в строку, вызываяtoString
для каждого элемента массива.@Юсаф, верно. Преобразование массивов в строки в JS дает тот же результат, что и
array.join(',')
.