Как обновить/добавить элемент массива в JavaScript?

Как я могу обновить/добавить элемент в массив?

var persons = {
    data: []
};

var bob = {name: 'Bob', age: 15};
var fill = {name: 'Fill', age: 20};
var mark = {name: 'Mark', age: 19};
var john = {name: 'John', age: 4};

persons['data'].push(bob);
persons['data'].push(fill);
persons['data'].push(mark);
persons['data'].push(john);

var updatedJohn = {name: 'John', age: 100};

if (!persons['data'][updatedJohn.name]){
    persons['data'].push(updatedJohn);
} else {
    persons['data'][updatedJohn.name] = updatedJohn; // this line doesn't work
}

Я не могу понять, как обновить элемент массива, если элемент John уже существует.

ОБНОВЛЕНИЕ

Пример jsFiddle

Ответ 1

Вам понадобится функция запроса, подобная следующей, чтобы помочь вам найти индексы в соответствии со свойством в вашей базе данных: (JSFiddle)

function findIndexByProperty(data, key, value) {
    for (var i = 0; i < data.length; i++) {
        if (data[i][key] == value) {
            return i;
        }
    }
    return -1;
}

var johnIndex = findIndexByProperty(persons.data, 'name', 'John');
if (johnIndex > -1) {
    persons.data[johnIndex] = updatedJohn;
} else {
    persons.data.push(updatedJohn);
}

Обратите внимание, что это возвращает только первую запись с именем John. Вам нужно будет решить, что вы хотите сделать в случае нескольких таких записей - обновить их все? Проблема такого рода заключается в том, что базы данных обычно имеют уникальные ключи для идентификации записей.

Если вы используете Underscore, у вас уже есть функция _.findIndex(), которую можно использовать вместо этого:

var johnIndex = _.findIndex(persons.data, { name: 'John' }); 

Ответ 2

Почему бы не использовать ассоциированный массив для persons['data'], потому что .push() просто использует массивы индексов

var persons = {
   data: {}
};

...
persons['data'][john.name] = john;
...

var updatedJohn = {name: 'John', age: 100};

// if statement isn't neccesary no more bc
// if the index is there it will override it and if not
// it will create a new index
persons['data'][updatedJohn.name] = updatedJohn;

Строка не работает для вас, потому что массив person был проиндексирован целыми числами persons['data'].push() вместо строк persons['data'][stringIndex]

Ответ 3

Массивы в javascript индексируются по номерам (или, по крайней мере, должны быть).

persons['data'].push(bob);
persons['data'].push(fill);
persons['data'].push(mark);

Использование persons[2] даст вам {name: 'Mark', age: 19}.

В то время как Javascript настолько гибкий, что вы можете делать так, как в @Sasa, отвечать и использовать строковые индексы, вы можете получить kneecapped другими разработчиками, если вы это сделаете, так как это ОЧЕНЬ ПЛОЩАДЬ.

[ADDED] Рассмотрим эти примеры странного и неожиданного поведения:

var ary = [];
ary[0] = false;
ary['using string indexes in javascript arrays is stupid'] = true;
console.log('pop should return the last added element', ary.pop()); //  false - WTF?
console.log('lastIndexOf should be 1?', ary.lastIndexOf(true)); // -1 WTF?

Массивы в Javascript должны использоваться как стеки. Подумайте о стопке карточек, вы либо добавите (нажмите), либо заберите карты (потяните), но вы не знаете, какая карта есть (если вы не обманываете).

Если вам нужен список лиц по имени, вы должны использовать объект для хранения людей:

persons.data = {};
persons['data']['Bob'] = bob;

Или, альтернативно, вы можете filter массив получить значения, которые соответствуют предикату:

bob = persons.data.filter(function(person){
  return person["name"] === 'Bob';
})[0];

EDIT:

Пример функции, которая создавала бы или находила человека:

var persons = { data : [] }
persons.data.push({ name: 'Bob', age: 10 })

// returns the index of the newly added person
persons.addOrReplace = function(new_person, attr) {

    var attr = attr || 'name';
    var data = this.data;    
    for (var i = 0; i < data.length; i++) {
      if (data[i][attr] === new_person[attr]) {
        data[i] = new_person;
        return i;
      }
    }   
    return this.data.push(new_person);
}

persons.addOrReplace({ name: 'Bob', age: 11 });
console.log(persons.data.length); // 1
console.log(persons.data[0].age); // 11

persons.addOrReplace({ name: 'Joe', age: 11 });
console.log(persons.data.length); // 2
console.log(persons.data[persons.data.length -1].name); // Joe

Ответ 4

Попробуйте выполнить итерацию через элементы объекта persons, обновите элемент, если член с тем же именем существует, если он этого не делает, нажмите новый элемент в массив. Используйте новую переменную exists, чтобы проверить, существует ли элемент.

Вот что вы могли бы сделать:

var persons = {
    data: []
};

var bob = {name: 'Bob', age: 15};
var fill = {name: 'Fill', age: 20};
var mark = {name: 'Mark', age: 19};
var john = {name: 'John', age: 4};

persons['data'].push(bob);
persons['data'].push(fill);
persons['data'].push(mark);
persons['data'].push(john);

var updatedJohn = {name: 'John', age: 100};

var exists = 0;

for (var i=0; i<persons['data'].length; i++) {
    if (persons['data'][i].name == updatedJohn.name) {
        persons['data'][i].age = updatedJohn.age;
        exists = 1;
    }
}

if (exists === 0)
    persons['data'].push(updatedJohn);

Вот вы обновленный скрипт: http://jsfiddle.net/t4kjgkcn/3/

Ответ 5

Вы можете создать таблицу поиска для каждого существующего человека, если она не находится в ней, вы нажимаете ее в файлах people.data и создаете новую запись в таблице поиска, иначе вы переписываете полный объект person без нарушения приведенной ссылки на значение. (Я написал комментарий, чтобы объяснить эту часть).

JSFiddle здесь

var persons = {
    data: []
};

var bob = {name: 'Bob', age: 15};
var fill = {name: 'Fill', age: 20};
var mark = {name: 'Mark', age: 19};
var john = {name: 'John', age: 4};

persons['data'].push(bob);
persons['data'].push(fill);
persons['data'].push(mark);
persons['data'].push(john);

var personsHash = {};

// store an external reference for each persons
for (var i = 0, l = persons.data.length; i < l; i++) {
    personsHash[persons.data[i].name] = persons.data[i];
}

var updatedJohn = {name: 'John', age: 100};

if (!personsHash[updatedJohn.name]){
    personsHash[updatedJohn.name] = updatedJohn;
    persons['data'].push(updatedJohn);
} else {
    var key;
    var person = personsHash[updatedJohn.name];
    // comment if you don't want a full rewrite but just an update of attributes
    /**/
    for (key in person) {
        delete person[key];
    }
    /**/
    for (key in updatedJohn) {
        if (updatedJohn.hasOwnProperty(key)) {
            person[key] = updatedJohn[key];
        }
    }
}

Ответ 6

function addOrUpdate(arr, comp, update) {
  if (arr) {
    var updated = false;
    arr.map(function(e, i) {
      var found = e[comp] == update[comp];
      if (found) {
        angular.extend(arr[i], update);
        updated = true;
      }
    });
    if (!updated) {
      arr.push(update);
    }
  }
}

//example

var a = [{
  id: 1,
  name: 'a'
}, {
  id: 2,
  name: 'b'
}, {
  id: 3,
  name: 'c'
}];

addOrUpdate(a, "id", {
  id: 4,
  name: 'e3333'
});
//looks for an elemnent with id=4, doesnt find, and adds it

addOrUpdate(a, "id", {
  id: 4,
  name: 'e5555'
});
//this time it will find and update the name