JavaScript, перезаписать объект без потери ссылки
приложение
Я работаю над простым веб-приложением, которое построено поверх AngularJS. Приложение должно иметь возможность работать как в автономном режиме, так и в интернете. Когда пользователь находится в автономном режиме, изменения в данных хранится локально. Поэтому идентификаторы, которые используются в этом приложении в автономном режиме, являются только временными идентификаторами, они заменяются при загрузке на сервер
данные, которые используются в приложение состоит из сложных объектов (с отношениями/ссылками на другие объекты). Когда я сохраняю на сервере, я хотел, чтобы представления обновлялись с новыми" реальными " идентификаторами.
Однако, поскольку JavaScript работает с объектами в качестве ссылок, я не могу сделать то, что хочу:$scope.data = newdata
Это не перезапись $scope.данные, но создает новый объект. Старая ссылка на старые данные все еще существует.
упрощенный
var x = {id: 1, name: "myObject"}
var c = x // c = {id: 1, name: "myObject"}
x = {id: 2, name: "myNewObject"}
// c = {id: 1, name: "myObject"}
Как вы можете видеть, c все еще ссылка на старый объект. На практике это приводит к тому, что мое представление не обновляется новыми данными, поскольку оно все еще привязано к старым данным. Что мне нужно, так это перезаписать свойства, в этом примере, x. Мне нужно сделать это рекурсивно, так как мои реальные объекты сложны, однако он не должен вводить никаких круговых ссылок, так как это, вероятно, вызовет переполнение стека. Если я перезаписываю a с b, а A имеет свойства, которых у b нет, эти свойства должны быть удаленный.
что мне нужно
мне нужна какая-то функция, которая перезаписывает все свойства в a (старый объект) со свойствами в b (новый объект). Все свойства, существующие в a, но не в b, должны быть удалены.
4 ответов
Я нашел решение после некоторых раздумий. Это, вероятно, не самое эффективное решение, но оно делает работу за меня. Сложность времени, вероятно, может быть лучше, и все предложения по улучшению приветствуются. Первый параметр-это объект, который нужно расширить, второй-тот, который нужно расширить. Третий должен быть логическим, указывающим, следует ли удалять свойства в a, которые не существуют в b или нет.
function extend(_a,_b,remove){
remove = remove === undefined ? false : remove;
var a_traversed = [],
b_traversed = [];
function _extend(a,b) {
if (a_traversed.indexOf(a) == -1 && b_traversed.indexOf(b) == -1){
a_traversed.push(a);
b_traversed.push(b);
if (a instanceof Array){
for (var i = 0; i < b.length; i++) {
if (a[i]){ // If element exists, keep going recursive so we don't lose the references
a[i] = _extend(a[i],b[i]);
} else {
a[i] = b[i]; // Object doesn't exist, no reference to lose
}
}
if (remove && b.length < a.length) { // Do we have fewer elements in the new object?
a.splice(b.length, a.length - b.length);
}
}
else if (a instanceof Object){
for (var x in b) {
if (a.hasOwnProperty(x)) {
a[x] = _extend(a[x], b[x]);
} else {
a[x] = b[x];
}
}
if (remove) for (var x in a) {
if (!b.hasOwnProperty(x)) {
delete a[x];
}
}
}
else{
return b;
}
return a;
}
}
_extend(_a,_b);
}
используя метод "extend", который доступен в подчеркивании и jquery:
//Clear all the 'old' properties from the object
for (prop in old_object) {delete old_object[prop]}
//Insert the new ones
$.extend(old_object, new_object)
я добавляю ответ, хотя все объяснили, почему и решения.
причина, по которой я добавляю ответ, заключается в том, что я искал этот ответ несколько раз за эти годы и всегда в основном приходил к тем же 2/3 вопросов SO. Я поместил решения в слишком жесткую корзину, потому что код, с которым я работал, имеет много модулей, следующих аналогичным шаблонам проектирования; просто было слишком много работы, чтобы попытаться решить то, что сводилось к той же проблеме, что и вы имеющий.
то, что я узнал, и, надеюсь, это имеет некоторое значение для других, теперь, когда я фактически пересмотрел нашу кодовую базу, чтобы избежать этой проблемы (иногда, возможно, ее неизбежно, но иногда это определенно так),-это избегать использования "статических частных переменных" для ссылок на объекты.
Это, вероятно, может быть больше genericised, но возьмем к примеру:
var G = {
'someKey' : {
'foo' : 'bar'
}
};
G.MySingletonClass = (function () {
var _private_static_data = G.someKey; // referencing an Object
return {
/**
* a method that returns the value of _private_static_data
*
* @method log
**/
log: function () {
return _private_static_data;
} // eom - log()
}; // end of return block
}()); // end of Class
console.log(G.MySingletonClass.log());
G.someKey = {
'baz':'fubar'
};
console.log(G.MySingletonClass.log());
http://jsfiddle.net/goxdebfh/1/
как вы можете видеть, то же самое проблема, испытываемая спрашивающим. В моем случае, и это использование частных статических переменных, ссылающихся на объекты, было везде, все, что мне нужно было сделать, это напрямую искать G.someKey;
вместо того, чтобы хранить его как переменную удобства для моего класса. Конечный результат (хотя и более длинный в результате неудобства) работает очень хорошо:
var G = {
'someKey' : {
'foo' : 'bar'
}
};
G.MySingletonClass = (function () {
return {
/**
* a method that returns the value of _private_static_data
*
* @method log
**/
log: function () {
return G.someKey;
} // eom - log()
}; // end of return block
}()); // end of Class
console.log(G.MySingletonClass.log());
G.someKey = {
'baz':'fubar'
};
console.log(G.MySingletonClass.log());
http://jsfiddle.net/vv2d7juy/1/
Так что да, возможно, ничего нового, учитывая, что вопрос был решен, но я чувствовал себя обязанным поделитесь этим, потому что я даже поверил, что первый пример был правильным способом делать вещи. Может быть, в некоторых случаях, это наверняка не получится.
надеюсь, что это поможет кому-то, где-то!