JavaScript,覆盖对象而不会丢失引用

Ant*_*and 12 javascript javascript-objects

应用

我正在开发一个构建在AngularJS之上的简单Web应用程序.该应用程序应该能够脱机工作以及在线工作.当用户离线时,对数据的更改将存储在本地.因此,在离线模式下此应用程序中使用的id只是临时id,在上传到服务器时会被替换

问题

应用程序中使用的数据由复杂对象组成(具有对其他对象的关系/引用).当我保存到服务器时,我希望视图能够使用新的"真实"ID进行更新.但是,由于JavaScript使用对象作为引用,因此无法执行我想要的操作:$scope.data = newdata 这不会覆盖$ scope.data,而是创建一个新对象.旧数据的旧引用仍然存在.

简化示例

var x = {id: 1, name: "myObject"}
var c = x    // c = {id: 1, name: "myObject"}
x = {id: 2, name: "myNewObject"} 
// c = {id: 1, name: "myObject"}
Run Code Online (Sandbox Code Playgroud)

如您所见,c仍然是对旧对象的引用.实际上,这会导致我的视​​图没有使用新数据更新,因为它仍然绑定到旧数据.我需要的是覆盖在这个例子中x的属性.我需要以递归方式执行此操作,因为我的实际对象很复杂,但是它不应该输入任何循环引用,因为这可能会导致堆栈溢出.如果我用b覆盖a并且a具有b未获得的属性,则应删除这些属性.

我需要的

我需要某种功能,用b(新对象)中的属性覆盖(旧对象)中的所有属性.应删除存在于但不存在于b中的所有属性.

Ant*_*and 5

经过一番思考,我找到了解决方案.它可能不是最有效的解决方案,但它确实适合我.时间复杂度可能会更好,所有改进建议都是值得欢迎的.第一个参数是要扩展的对象,第二个是要扩展的对象.第三个应该是一个布尔值,表示是否应该删除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);
    }
Run Code Online (Sandbox Code Playgroud)


Bob*_*off 5

使用下划线和jquery中可用的“ extend”方法:

//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)
Run Code Online (Sandbox Code Playgroud)


Nic*_*iwi 5

如果您的环境支持ECMAScript 2015,则可以使用Object.assign()

'use strict'

let one = { a: 1, b: 2, c: 3 };
let two = { b: 20, c: 30, d: 40 };

let three = Object.assign({}, one, two);

console.log(three);

// will output: Object {a: 1, b: 20, c: 30, d: 40}
Run Code Online (Sandbox Code Playgroud)

let是的新局部范围的版本var在2015年的ECMAScript)更多..


因此,在您的简单示例中:

var x = { id: 1, name: "myObject" };
Object.assign(x, { id: 2, name: "myNewObject" });

console.log(x);

// will output: Object {id: 2, name: "myNewObject"}
Run Code Online (Sandbox Code Playgroud)