#javascript #ecmascript-6
#javascript #ecmascript-6
Вопрос:
При объявлении объектных литералов можно объявлять динамические ключи следующим образом:
const foo = 'foo';
const obj = {
[foo]: 'bar'
}
console.log(obj);
Этот синтаксический сбой для массивов, потому что квадратная скобка интерпретируется как объявление массива, тогда синтаксический анализатор завершается ошибкой при достижении двоеточия. Пример варианта использования: клонирование массива при изменении последнего элемента:
const arr = [1, 2, 3];
const modifiedClone = [...arr, [arr.length - 1]: 4]; // Fails
Существует ли синтаксис для объявления динамических индексов для литералов массива?
Комментарии:
1. С литералом массива вы можете объявить массив только с его элементами. Вы не можете сделать то же самое, что и распространение объекта, потому что принципиально синтаксис массива работает не так — вы не определяете элементы по их позиции, вы просто определяете последовательность, которая превращается в массив.
2. Просто написать
const modifiedClone = [...arr]; modifiedClone[arr.length - 1] = 4;
?3. @Bergi да, очевидно, но мой вопрос касается одной инструкции для достижения этой цели
4. Вы можете поместить все в IIFE, если хотите сделать это одним выражением 🙂
5. Есть предложение, которое позволит вам пропускать и перематывать итераторы . С этим можно было бы быть более гибким и / или с помощниками итератора . Если вы хотите как распространять, так и перезаписывать, вы можете использовать для этого генераторы. Стоит ли это того, зависит, но это вариант.
Ответ №1:
Вы могли бы использовать Object.assign
пустой массив в качестве целевого объекта, а также данный массив и объект со свойством index.
const arr = [1, 2, 3];
const modifiedClone = Object.assign([], arr, { [arr.length - 1]: 4 });
console.log(modifiedClone);
Ответ №2:
То, что вы запрашиваете, в настоящее время невозможно с использованием литерала массива и синтаксиса распространения. Это потому, что, в отличие от объектных литералов, массив определяется не конкретными индексами, а последовательностью, которая становится его членами.
Самое большее, вы можете использовать elision, чтобы оставить индекс пустым, например, [1, , 3]
будет производить 1, <empty>, 3
, но вы все равно должны четко указать это, вы не можете «пропустить», это означает, что создание массива только с первым и десятым элементом становится очень сложным [1,,,,,,,,,10]
. Наличие большего количества определенно не рекомендуется в качестве литерала массива.
С учетом сказанного синтаксис распространения ...
с массивами принимает значения из итератора, поэтому [...arr]
он похож на:
let result = [];
let it = arr[Symbol.iterator]();
let next = it.next();
while (!next.done)) {
result.push(next.value);
next = it.next();
}
Обладая этими знаниями, мы можем использовать функции генератора и создать несколько простых универсальных вспомогательных генераторов, которые преобразуют итерацию и распространяют свои результаты. Например
Получить все, кроме последнего элемента, из итерируемого:
/**
*
* @generator
* @param {Iterable}
* @yields {*} every value from the iterable but the last one
*/
function* initial(iterable) {
const it = iterable[Symbol.iterator]();
let last = it.next();
let next = it.next();
while(!next.done){
yield last.value;
last = next;
next = it.next();
}
}
const arr = [1, 2, 3];
const modifiedClone = [...initial(arr), 4];
console.log(modifiedClone);
Возьмите первые num
значения из итерируемого:
/**
*
* @generator
* @param {number} num - how many items to extract
* @param {Iterable} itearable - iterable from where the results should be extracted
* @yields {*} - at most `num` amount of results from `iterable`
*/
function* take(num, iterable) {
const it = iterable[Symbol.iterator]();
let {value, done} = it.next();
for (let i = 0; i < num amp;amp; !done; i , {value, done} = it.next()) {
yield value;
}
}
const arr = [1, 2, 3];
const modifiedClone = [...take(arr.length - 1, arr), 4];
console.log(modifiedClone);
Перейдите к итерируемому и преобразуйте значение там, где это необходимо:
/**
* transform an iterable of key-value pairs by their key
*
* @generator
* @param {Map} replacements - new values for each of the keys
* @param {Iterable} keyValueIterable - iterable which produces `[key, value]` pairs
* @yields {*} - the values of the iterable transformed where needed
*/
function* replaceByKey(replacements, keyValueIterable) {
const it = keyValueIterable[Symbol.iterator]();
for (let {value: pair, done} = it.next(); !done; {value: pair, done} = it.next()) {
let [key, value] = pair;
if (replacements.has(key))
yield replacements.get(key);
else
yield value;
}
}
const arr = ["a", "b", "c", "d", "e"];
const replace = new Map()
.set(1, "foo")
.set(arr.length-1, "bar");
const modifiedClone = [...replaceByKey(replace, arr.entries())];
console.log(modifiedClone);
Доступно больше возможностей в зависимости от того, что необходимо.