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