#javascript
#javascript
Вопрос:
Привет, я действительно не знал, как написать заголовок для этого поста, но у меня есть вопрос. Допустим, у меня есть объект внутри функции, который я хочу заполнить данными, отправленными в качестве аргумента оператора распространения. Я перебираю данные с помощью forEach. Моя проблема в том, что только последние аргументы помещаются в конечный массив результатов.
Чтобы прояснить мою проблему, вот несколько демонстрационных кодов:
let result = [];
function takeArgs(...args) {
let obj = {
string: "",
num: 0
}
args.forEach(e => {
if (typeof(e) === "string") obj.string = e;
else {
obj.num = e;
result.push(obj);
}
});
}
takeArgs("Some string", 10, "Some other string", 15);
console.log(result);
Итак, если бы я должен был регистрировать массив результатов, я бы получил «Какую-то другую строку», 15 дважды в результирующем массиве. Почему это происходит?
Ответ №1:
Ваша проблема в том, что вы создаете ссылку на объект obj
в замыкании. obj
передается по ссылке, поэтому он всегда один и тот же, и поэтому он переопределяется. Попробуйте создать новый объект на каждой итерации цикла:
let result = []
function takeArgs(...args) {
args.forEach(e => {
let obj = {
string: "",
num: 0,
}
if (typeof(e) === "string") obj.string = e;
else {
obj.num = e;
}
result.push(obj);
});
}
takeArgs("Some string", 10, "Some other string", 15)
console.log(result)
РЕДАКТИРОВАТЬ: вероятно, в вашем ветвлении if-else также есть недостаток: вы нажимаете только obj
result
в том случае, если его тип не является строкой (или это ваше намерение?).
Комментарии:
1. Да, это недостаток в коде, спасибо, что указали на это: D
Ответ №2:
obj
это просто указатель на какое-то место в памяти. Нажатие его дважды в массив — это то же самое, что нажатие двух указателей, независимо от того, насколько сильно вы меняете их с push на push — все они будут затронуты этим.
Используя очень чистый синтаксис es6
, вы можете предотвратить эту проблему, просто добавив синтаксис spread в строку 12:
result.push({...obj});
let result = [];
function takeArgs(...args) {
let obj = {
string: "",
num: 0
}
args.forEach(e => {
if (typeof(e) === "string") obj.string = e;
else {
obj.num = e;
result.push({...obj});
}
});
}
takeArgs("Some string", 10, "Some other string", 15);
console.log(result);
Синтаксис spread создает новый экземпляр объекта с текущим содержимым obj
, или, другими словами, указатель на другое место в памяти. Таким образом, предыдущий obj
и текущий больше не связаны
Ответ №3:
Это потому, что вы создаете один объект, который вы изменяете в своем цикле. Таким образом, конечное состояние этого объекта будет с последней итерации в цикле. Затем вы помещаете ссылку на объект в цикл. Это приведет к тому, что каждый объект в массиве является одним и тем же объектом.
Вместо этого создайте новый объект для каждого элемента в цикле и передайте его в массив результатов.
let result = [];
function takeArgs(...args){
args.forEach(e => {
let obj = {
string: "",
num: 0
}
if (typeof(e) === "string") {
obj.string = e;
} else {
obj.num = e;
result.push(obj);
}
});
}
takeArgs("Some string", 10, "Some other string", 15);
Однако это приведет к перемещению объекта в массив результатов только в том случае, если тип значения равен a number
. Поэтому вы, вероятно, захотите добавить некоторую логику для разделения аргументов на группы по два, чтобы у вас были пары строк и чисел.
let result = [];
function takeArgs(...args){
for (let i = 0; i < args.length; i = 2) {
let obj = {
string: args[i],
num: args[i 1]
}
result.push(obj);
}
}
takeArgs("Some string", 10, "Some other string", 15);
console.log(result);
Комментарии:
1. Я даже не думал об использовании obj для хранения таких данных, спасибо: D