Я в настоящее время борется с проблемой JavaScript. Я хочу вернуть многоуровневое свойство, а также каждую переменную, содержащуюся внутри, путем передачи в исходном объекте и массива путей к свойствам, которые я хочу.
Например, если у меня есть следующий объект:
obj = {
product: {
candidate: {
id: 10,
reference: "test",
count: 4,
steps: 10
}
}
}
Я хочу иметь возможность вызвать метод:
getVarPath(obj, ["product.candidate.ID", "product.candidate.reference"])
И затем пусть он возвращает один объект с каждой переменной, переданной в массиве, в ней исходная структура. Таким образом, это вернет объект, выглядящий так:
{
product: {
candidate: {
id: 10,
reference: "test"
}
}
}
На данный момент у меня это работает в моем локальном решении (передавая только одну строку, а не массив).
Решение на данный момент довольно ужасное, но я хочу улучшить его, поэтому, если кто-нибудь может подумать о лучшем методе, который будет замечательным. Опять же, сейчас это довольно ужасно, но я хочу улучшить его. Но он выполняет эту работу:
var getVarPath = function(obj, keys){
var elements = keys.split("."),
evalStr = "",
objStr = "obj",
newObjStr = "newObj",
newObj = {};
if(elements.length > 1){
elements.forEach(function(key, index){
// first append a property accessor at the end of the eval string
evalStr = evalStr + "['" + key + "']";
// if we're at the last element, we've reached the value, so assign it
if(index === elements.length -1){
eval(newObjStr + evalStr + " = " + objStr + evalStr);
}
else {
// if we're not at the last, we're at an object level
// if the nested object doesn't exist yet, create it
if(!eval(newObjStr + evalStr)){
eval(newObjStr + evalStr + " = {};");
}
}
});
}
return newObj;
}
Используя _.propertyOf()
, Array#reduce()
и Object.assign()
, а также имена вычисляемых свойств, вы можете создать менее сложную реализацию:
function getVarPath(object, paths) {
return paths.reduce(function (accumulator, path) {
const that = _.propertyOf(accumulator)
let walk = path.split('.')
let value = this(walk)
for (let key = walk.pop(); key !== undefined; key = walk.pop()) {
const base = that(walk)
value = { [key]: value }
if (base !== undefined) {
value = Object.assign(base, value)
}
}
return Object.assign(accumulator, value)
}.bind(_.propertyOf(object)), {})
}
let obj = {
product: {
candidate: {
id: 10,
reference: "test",
count: 4,
steps: 10
}
}
}
console.log(getVarPath(obj, ['product.candidate.id', 'product.candidate.reference']))
<script src="https://cdn.rawgit.com/lodash/lodash/4.17.4/dist/lodash.min.js"></script>
Ваш код как есть, на самом деле не работает. Вы обрабатываете keys
как строку, но передаете массив. Вы можете (и должны) избегать использования eval()
, отслеживая "внутренние" объекты, которые вы сейчас просматриваете, и используя нотацию object[property]
вместо object.property
.
function getVarPath(obj, keys) {
var result = {};
// ["product.candidate.id", "product.candidate.reference"]
keys.forEach(function(key) {
var src = obj, // inner source object
dest = result, // inner destination object
parts = key.split(/\./);
// e.g. ["product", "candidate", "id"]
parts.forEach(function(part) {
// if we're looking at an object, make sure it exists in the dest
if (typeof(src[part]) === "object")
dest[part] = dest[part] || {};
// if it just a value, copy it
else
dest[part] = src[part];
dest = dest[part]; // move from obj to obj.product, then to obj.product.candidate, etc.
src = src[part];
});
});
return result;
}
var obj = {
product: {
candidate: {
id: 10,
reference: "test",
count: 4,
steps: 10
}
}
}
var output = getVarPath(obj, ["product.candidate.id", "product.candidate.reference"]);
console.log(JSON.stringify(output));
Для каждого элемента входного массива:
Во-первых, вы можете разбить начальную строку: var nestedElements="product.candidate.ID".split(.)"
Это возвращает массив с каждым уровнем: ["product","candidate","ID"]
Теперь вы можете получить доступ к вашему вложенному объекту с помощью каждого элемента массива: obj["product"]["candidate"]["ID"]
либо с помощью цикла по массиву, либо рекурсии.
var currentobj=obj;
for (var i=0;i<nestedElements.length;i++){
currentobj=currentobj[nestedElements[i]]
}
// currentobj is your id
В этом же процессе вы можете динамически добавлять элементы в новый объект с помощью аналогичного процесса:
newobj={} //before loop
if (newobj["product"] === undefined) newobj["product"]={} //in loop
И это должно быть сделано для каждого элемента входного массива, в конце - итерации через массивы и доступа к объекту с использованием строк