Javascript循环访问对象并插入丢失的密钥,即使在子代中也是

时间:2014-10-24 10:22:18

标签: javascript object nested

我需要同步两个javascript对象,我想用object1中的缺失键填充object2而不替换现有的,即使是嵌套的:

var object1 = {
    firstName: "Marco",
    lastName: "Rossi",
    favoriteFood: {firstCourse: "pasta", secondCourse: "salsiccia"},
    favoriteDrink: "Vino",
    favoriteSong: "O sole mio"
}

var object2 = {
    firstName: "Marco",
    lastName: "Rossi",
    favoriteFood: {firstCourse: "pasta"},
    favoriteSong: "Viaggiare"
}

我真的不知道如何进入嵌套键。特别是为了继续检查内巢,如果你有5个巢或类似的东西怎么办我知道如何处理第一级而不是进一步下降。

objec2的理想结果是

var object2 = {
    firstName: "Marco",
    lastName: "Rossi",
    favoriteFood: {firstCourse: "pasta", secondCourse: "salsiccia"},
    favoriteDrink: "Vino",
    favoriteSong: "Viaggiare"
}

提前感谢您的帮助。

7 个答案:

答案 0 :(得分:4)

您需要编写递归函数来处理嵌套对象。也许是这样的:

var object1 = {
    firstName: "Marco",
    lastName: "Rossi",
    favoriteFood: {firstCourse: "pasta", secondCourse: "salsiccia"},
    favoriteMovie: {rating: 7, title: "Monday"},
    favoriteDrink: "Vino",
    favoriteSong: "O sole mio"
}

var object2 = {
    firstName: "Marco",
    lastName: "Rossi",
    favoriteFood: {firstCourse: "pasta"},
    favoriteSong: "Viaggiare"
}

function fillObject(from, to) {
    for (var key in from) {
        if (from.hasOwnProperty(key)) {
            if (Object.prototype.toString.call(from[key]) === '[object Object]') {
                if (!to.hasOwnProperty(key)) {
                    to[key] = {};
                }
                fillObject(from[key], to[key]);
            }
            else if (!to.hasOwnProperty(key)) {
                to[key] = from[key];
            }
        }
    }
}

fillObject(object1, object2);

alert( JSON.stringify(object2, null, '    ') );

注意:如果您想知道这一行Object.prototype.toString.call(from[key]) - 这是为了可靠地检查该值是否为对象,因为typeof null也报告object

答案 1 :(得分:1)

for(var prop in object1){
    if(object1.hasOwnProperty(prop)){
        if(!(prop in object2)){
            object2[prop] = object1[prop];
        }
    }
}

答案 2 :(得分:1)

这对我有用。我觉得它非常简单。只需检查object2中是否存在属性,否则将其复制(如果它不是对象)。如果它是一个对象递归。

 (function(){
    console.log("EXECTURING");
    var object1 = {
        firstName: "Marco",
        lastName: "Rossi",
        favoriteFood: {firstCourse: "pasta", secondCourse: "salsiccia"},
        favoriteDrink: "Vino",
        favoriteSong: "O sole mio"
    };

    var object2 = {
        firstName: "Marco",
        lastName: "Rossi",
        favoriteFood: {firstCourse: "pasta"},
        favoriteSong: "Viaggiare"
    };

    for( key in object1) {
        if(object1.hasOwnProperty(key)) {
            copyToB(key, object1, object2);
        }
    }
})();

function copyToB(key, o1, o2) {
    if(typeof(o1[key]) !== "object") {
        if(typeof o2[key] === "undefined")
            o2[key] = o1[key];
        return;
    }

    var tempObj = o2[key];
    for(k in  o1[key]) {
        copyToB(k, o1[key], tempObj);
    }
    o2[key] = tempObj;
}

答案 3 :(得分:0)

执行此操作的一种方法是检查typeof()每个对象属性并以递归方式遍历。

答案 4 :(得分:0)

您需要浏览完整的对象并询问键/值对的变量类型。如果它是一个对象,请再次执行。

fiddle中的迷你示例。

$.each(object1, function( index, value ) {        
    console.log( index + ": " + typeof(value) );
});

(我将离开,但Crossfires版本已经更快更完整了)

答案 5 :(得分:0)

function sync(source, target) {
    if(getType(source) !== 'object' || getType(target) !== 'object') {
        return;
    }
    for(var p in source) {
        if(getType(target[p]) === 'object') {
            if(getType(target[p]) !== 'object') {
                target[p] = {};
            }
            sync(source[p], target[p]);
        } else if(getType(target[p]) === 'null' || getType(target[p]) === 'undefined'){
            target[p] = source[p];
        } 
    }
};

function getType(arg) {
    if(arg === null) {
        return 'null';
    } else if(arg === undefined) {
        return 'undefined';
    }
    var type = Object.prototype.toString.call(arg);
    return type.slice(8, type.indexOf(']')).toLowerCase();
};

答案 6 :(得分:0)

如果目标中的路径为null,则所有这些答案都将失败,因此有必要在递归之前向对象深1级查找,并检查目标节点是否为null,如果是,则在递归之前对其进行更新

注意:我的答案采用的论点顺序与其他人不同。 a是要检查缺少键的项目,b是具有正确键的参考对象。对于是否对a进行了任何更改,我的函数还返回true / false。还会在缺少键时将默认值从b复制到a。

function has (o,k) {
    return typeof o==='object'&&(o.hasOwnProperty(k)||o[k]!==undefined);
}

function recursiveCheck( a, b ) {
    var c = false;//whether we have changes. the calling scope wants to know
    // a is the object to check, b is the target
    for(let k in b) {
        if(!has(a,k)) {
            c=true;
            a[k] = b[k];
        }else{
            // if b[k] is an object, we recursively check on the children for changes
            // we only want to manipulate a[k] if b[k]=== object and not null!!!
            if(typeof b[k]==='object'&&b[k]!==null){
                for(let k2 in b[k]) {
                    if(a[k]===null){
                        a[k]=b[k];
                        c=true;
                    }
                    if( (!has(a[k],k2) || a[k][k2]===null) && typeof b[k][k2]==='object' && b[k][k2]!==null){
                        a[k][k2] = b[k][k2];
                        c=true;
                    }
                }
                const hasChange = recursiveCheck(a[k],b[k]);
                c = c || hasChange;
            }
        }
    }
    return c;
}

用法

var a = { foo: null, bar: true };//this is the object we are checking 
var b = { foo:{test:1,hello:false},bar: false}; //this is the object with correct keys and default values that should copy over to a when needed.

const didChange = recursiveCheck(a,b);

证明正确输出的测试用例

var target = {
    private:{
        has:false,
        cost:0
    },
    shared:{
        has:false,
        cost:0
    }
}

var inputs = [
    {},// true
    {private:null,shared:null},// true
    {private:{has:true},shared:{cost:50}},// true
    {private:{has:true,cost:500},shared:{has:false,cost:250}}// false
];

console.log('inputs---',inputs);

const results = inputs.map(item=>recursiveCheck(item,target));

console.log('inputs(transformed)---',inputs);

console.log('results---',results); // should be [true, true, true, false]