2015-09-28 1 views
3

У меня есть знак подчеркивания.Как частично обновить вложенный объект, учитывая ключ как строку?

у меня есть:

var person = { 
    personal: { 
    fname: 'Victor', 
    lname: 'Lee', 
    address: { 
     street: '1234 Main', 
     state: { 
     abbrName: 'CA', 
     fullName: 'California', 
     timezone: 'PST' 
     }, 
     zip: '94043' 
    } 
    } 
}; 

Я хотел бы обновить несколько свойств, но оставить нетронутыми другие.

Вместо того, чтобы писать три отдельные линии:

person.personal.address.state.abbrName = 'OR'; 
    person.personal.address.state.fullName = 'Oregon'; 
    person.personal.address.zip = '97062'; 

Я хочу, чтобы иметь возможность установить весь реквизит в одной строке коды, но и оставить другие свойства нетронутыми.

Если я:

_.extend(person.personal.address, { 
    state: { 
    abbrName: 'OR', 
    fullName: 'Oregon' 
    }, 
    zip: '97032' 
}); 

Результирующий объект имеет часовой пояс вырубали:

{ 
    personal: { 
    fname: 'Victor', 
    lname: 'Lee', 
    address: { 
     street: '1234 Main', 
     state: { 
     abbrName: 'CA', 
     fullName: 'California', 
     }, 
     zip: '94043' 
    } 
    } 
}; 

Нечто подобное было бы идеально:

var updateObj = function(obj, key, value){ 
    // stuff 
    return obj; 
}; 

и бежать, как:

updateObj(person, 'personal.address', { 
    state: { 
    abbrName: 'OR', 
    fullName: 'Oregon' 
    }, 
    zip: '97032' 
}); 

Пока у меня это есть, но он полностью перезаписывает одно свойство за раз.

var updateObjectWithStringKey = function(obj, key, value) { 
    if (typeof key === "string"){ 
    key = key.split("."); 
    }; 

    if (prop.length > 1) { 
    var e = key.shift(); 
    updateObjectWithStringKey(obj[e] = 
     typeof obj[e] == 'object' ? obj[e] : {}, 
     key, 
     value); 
    } else { 
    obj[key[0]] = value; 
    }; 

    return obj; 

}; 

EDIT

Хорошо, я думаю, что я близко:

var MergeRecursive = function(destination, source) { 

    for (var p in source) { 

    if (typeof source[p] == 'object') { 
     destination[p] = MergeRecursive(destination[p], source[p]); 
    } else { 
     destination[p] = source[p]; 
    }; 

    }; 

    return destination; 

}; 

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

var person = { 
    personal: { 
    fname: 'Victor', 
    lname: 'Lee', 
    address: { 
     street: '1234 Main', 
     state: { 
     abbrName: 'CA', 
     fullName: 'California', 
     timezone: 'PST' 
     }, 
     zip: '94043' 
    } 
    } 
}; 

var updatedInfo = { 
    personal: { 
    address: { 
     state: { 
     abbrName: 'OR', 
     fullName: 'Oregon', 
     capital: 'Salem' 
     }, 
     zip: '97062' 
    }, 
    } 
}; 

MergeRecursive(person, updatedInfo); 

{ 
    personal: { 
    fname: 'Victor', 
    lname: 'Lee', 
    address: { 
     street: '1234 Main', 
     state: { 
     abbrName: 'OR', 
     fullName: 'Oregon', 
     timezone: 'PST', 
     capital: 'Salem' 
     }, 
     zip: '97062' 
    } 
    } 
} 

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

updateObj(person, 'personal.address', { 
    state: { 
    abbrName: 'OR', 
    fullName: 'Oregon', 
    capital: 'Salem' 
    }, 
    zip: '97062' 
}); 

Эта функция делает это, но не с поведением слияния выше :

var updateObjectWithStringProp = function(obj, prop, value) { 

    if (typeof prop === "string") { 
    var prop = prop.split('.'); 
    } 

    if (prop.length > 1) { 
    var p = prop.shift(); 
    if (obj[p] == null || typeof obj[p] !== 'object') { 
     obj[p] = {}; 
    } 
    updateObjectWithStringProp(obj[p], prop, value); 
    } else { 
    obj[prop[0]] = value; 
    } 

    return obj; 

}; 

Как отредактировать эту функцию, чтобы также включить слияние?

+1

В частном случае, описанном выше, есть причина, почему вы не попробовать '_.extend (person.personal.address, {состояние: 'МО', почтовый индекс: 44444})'? –

+1

Любая причина, по которой вы используете 'Object.prototype.toString.call (obj [e]) ===" [object Object] ", а не' typeof obj [e] == 'object''? – RobG

+0

Используйте функцию mergerecursive из [this] (http://stackoverflow.com/a/383245/502613) вопроса. Это сработает. – Jorg

ответ

-1

Возможно ли изменить вашу библиотеку от подчеркивания до lodash?

Тогда у вас будут такие же функции (и многое другое), в том числе _.defaultsDeep.

Вы можете выполнить слияние в одной отдельной строке, сохраняя часовой пояс посередине.

var person = { 
    personal: { 
    fname: 'Victor', 
    lname: 'Lee', 
    address: { 
     street: '1234 Main', 
     state: { 
     abbrName: 'CA', 
     fullName: 'California', 
     timezone: 'PST' 
     }, 
     zip: '94043' 
    } 
    } 
}; 
var update = { 
    personal: { 
    address: { 
     state: { 
     abbrName: 'OR', 
     fullName: 'Oregon' 
     }, 
     zip: '97032' 
    } 
    } 
} 
var result = _.defaultsDeep(update, person); 

Результата будет постановляет:

result = { 
    "personal":{ 
    "address":{ 
     "state":{ 
     "abbrName":"OR", 
     "fullName":"Oregon", 
     "timezone":"PST" 
     }, 
     "zip":"97032", 
     "street":"1234 Main" 
    }, 
    "fname":"Victor", 
    "lname":"Lee" 
    } 
} 
0

Вы можете использовать рекурсию, но помните, что она может иметь проблемы с большими объектами с высокой вложенностью.

Примечание: Вы должны рассмотреть несколько вещей, прежде чем сделать такую ​​функцию

  • Оба значения могут быть простой объект
  • Оба значения могут быть массив объектов
  • Оба значения могут быть массив
  • Новый объект могут иметь дополнительные параметры. Если вы разрешаете добавлять значения к исходному объекту?
  • Может ли исходный объект быть пустым? Если да, вы должны вернуть undefined или newValues?

Могут быть и другие параметры.

function mergeObject(source, newValue, allowNewProps) { 
    if (typeof newValue === "object" && typeof source === "object") { 
    for (var k in newValue) { 
     if (Array.isArray(newValue[k]) && Array.isArray(source[k])) { 
     for (var i = 0; i < newValue[k].length; i++) { 
      mergeObject(source[k][i], newValue[k][i]); 
     } 
     } 
     if (typeof newValue[k] === "object") { 
     mergeObject(source[k], newValue[k]); 
     } else if (source[k] !== undefined || allowNewProps) { 
     source[k] = newValue[k]; 
     } 
    } 
    } 
} 
Смежные вопросы