javascript возвращает ссылку на элемент массива
у меня есть такой массив:
users = [{id:1, name:'name1'},{id:2, name:'name2'}]
как я могу получить ссылку на элемент {id: 2, name:' name2'}, поэтому я могу изменить его свойство name, например:
user = get_item(users, 'id', 2);
user.name = "user2 name changed";
7 ответов
я пытался использовать
Array.filter()
функция, но она возвращает новый массив вместо ссылки на исходный массив. который я не могу использовать для мутации исходного массива.
он возвращает новый массив, но массив по записи по-прежнему ссылается на те же объекты. Так что filter
просто отлично для этого.
var filteredUsers = users.filter(function(entry) { return entry.id === 2; });
var item = filteredUsers[0];
item.name = "user2 name updated";
console.log(users[1].name) // "user2 name updated"
массив содержит ссылки к объектам, а не их копиям. Когда мы это сделаем item = users[1]
, или использовать filter
, чтобы получить новый массив, содержащий подмножество объектов, мы вам копию ссылки на объект, и поэтому переменная теперь ссылается на тот же объект, как это:
+-------+ | users | +-------+ | 0 |--------->+---------------+ | | | id: 1 | | | | name: "name1" | +---------------+ | | +---------------+ | filteredUsers | | | +---------------+ | 1 |--------->+---------------+<---------| 0 | | | | id: 2 | +---------------+ | | | name: "name2" | | | | | +------+ | | +---------------+<---------| item | +-------+ +------+
изменение объекта изменяет объект, и эти изменения видны независимо от того, какая ссылка на объект используется для просмотра его свойств.
теперь, если у вас массив примитивы:
var a = [1, 2, 3, 4, 5];
...тогда, конечно, вы не можете использовать подход выше, потому что они не объекты. В этом случае вы бы использовали indexOf
, чтобы найти индекс:
var index = a.indexOf(3); // Find the first entry === 3
...а затем измените запись
a[index] = 42;
это также относится к строкам (при условии, что они хорошие обычные примитивы строк, а не вещи, созданные с помощью new String()
, что практически никогда не нужно делать).
чтобы сделать это аналогично принятому ответу, но немного более кратко, давайте использовать массив.найти, например:
var item = users.find(u => u.id === 2)
item.name = "user2 name updated"
console.log(users[1].name) // "user2 name updated"
объяснения очень похожи на то, что было предусмотрено в принятой ответ.
или
users[1].name = "xx"
или если вы хотите искать по ID, как вы пытались сделать в вопрос:
for (i = 0; i < users.length; i++) {
if (users[i].id == "2") {
users[i].name = "xxx";
}
}
редактировать вы хотели что-то более продвинутое, как насчет использования map: (идея в том, что вы можете просто изменить элементы, соответствующие вашему запросу, и создать на его основе новый массив. вы можете использовать фильтр, чтобы отфильтровать их)
[{a: 1, b: 2}, {a:3, b:2}].map(function (elm) {
if (elm.b == 2) {
elm.a += 5;
}
return elm;
});
возвращает:
[{a: 6, b: 2}, {a:8, b:2}]
можно использовать findIndex(), например:
var users = [{id:1, name:'name1'},{id:2, name:'name2'}]
var idx = users.findIndex(item => item.id === 2);
var u = users[idx]; // the reference of user2
u.name = "name changed."; // same as `users[idx].name = "name changed.";`
проверить, если следующая функция решает вашу проблему.
Примечание : пользовательские объекты всегда передаются по ссылке в функцию JavaScript. При этом массив пользовательского объекта передается по ссылке.
function updateUser(targetArray, keyField, targetField, key, new_val) {
var result = -1;
for (var i = 0; i < targetArray.length; i++) {
if (targetArray[i][keyField] == key) {
targetArray[i][targetField] = new_val;
result = i;
return result;
}
}
return result;
}
вот код, который лучше объяснит сценарий. Запустите скрипт и поймете.
var arr = [
{"name": "James", "age": 34},
{"name": "Peter", "age": 67}
];
var p1 = arr.filter(function(p){return p.name=="James"});
p1[0] = {"name": "James", "age": 50};
console.log(JSON.stringify(arr)); // Won't work
var p2 = arr.filter(function(p){return p.name=="James"});
p2[0].age = 50;
console.log(JSON.stringify(arr)); // Voila... this works
аналогично ответу @zing-lee, вы можете удалить еще одну строку кода, используя find()
:
var users = [{id:1, name:'name1'},{id:2, name:'name2'}]
var user = users.find(item => item.id === 2)
user.name = 'name change'
из документов: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
возвращаемое значение: Значение первого элемента в массиве, которое удовлетворяет при условии тестирования функции
потому что это массив объекты (не примитивы), возвращаемое значение будет ссылка к исходному объекту, поэтому изменение свойства возвращаемого объекта обновит свойство объекта, на который он ссылается.
хорошая статья здесь, объясняющая значения и ссылки в Javasript: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0