2015-04-11 2 views
0

Я ищу способ ходить объект на основе массива и задать свойство для последнего ключа на объекте, например:Установить JavaScript свойства объекта путем обхода массива

var myArr = [ 'foo', 'bar', 'quz' ]; 
var myVal = 'somethingElse'; 
var myObj = { 
    foo: { 
     bar: { 
      quz: 'something' 
     } 
    } 
}; 

Я бы как иметь возможность изменить значение quz на somethingElse. Я пробовал рекурсировать, но я чувствую, что есть более простой способ сделать это.

Я искал lodash, но не могу найти метод, который, кажется, позволяет мне выполнить это.

+0

так что вы уже построили такой объект и хотите обновить значение? – ABOS

+0

Правильный, это объект конфигурации по умолчанию, который я ищу, чтобы иметь возможность переопределить. – Fluidbyte

+0

как насчет https://github.com/substack/js-traverse? – ABOS

ответ

1

Вы могли ходить объект так:

var myArr = [ 'foo', 'bar', 'quz' ], 
 
    myVal = 'somethingElse', 
 
    myObj = { 
 
     foo: { 
 
     bar: { 
 
      quz: 'something' 
 
     } 
 
     } 
 
    }; 
 

 
var obj= myObj; 
 
do { 
 
    obj= obj[myArr.shift()]; 
 
} while(myArr.length>1); 
 

 
obj[myArr[0]]= 'somethingElse'; 
 

 
document.body.innerHTML= JSON.stringify(myObj);


Update

Для решения @ проблем Томалак, а потому, что вы конкретно не запрещают рекурсивный решение, вот многоразовая функция без побочных эффектов (кроме изменения соответствующего значения obj ect):

function setObj(obj, arr, val) { 
    !(arr.length-1) && (obj[arr[0]]=val) || 
    setObj(obj[arr[0]], arr.slice(1), val); 
} 

Оценка короткого замыкания предотвращает это от бесконечного цикла.

Отрывок:

var myArr = [ 'foo', 'bar', 'quz' ], 
 
    myVal = 'somethingElse', 
 
    myObj = { 
 
     foo: { 
 
     lorem: 'ignore me', 
 
     bar: { 
 
      quz: 'something' 
 
     }, 
 
     other: { 
 
      quz: 'leave me be' 
 
     } 
 
     } 
 
    }; 
 

 
function setObj(obj, arr, val) { 
 
    !(arr.length-1) && (obj[arr[0]]=val) || 
 
    setObj(obj[arr[0]], arr.slice(1), val); 
 
} 
 

 
setObj(myObj, myArr, 'somethingElse'); 
 

 
document.body.innerHTML= JSON.stringify(myObj);

+1

Очень приятно, отлично работает и действительно чист. – Fluidbyte

+0

Собственно, это не очень чисто. Он не может использоваться повторно и модифицирует исходный массив, то есть он имеет нежелательные побочные эффекты. – Tomalak

+0

@Tomalak, хороший момент об изменении исходного массива. См. Мое обновление. –

0
var myArr = [ 'foo', 'bar', 'quz' ]; 
var myVal = 'somethingElse'; 
var myObj = { 
    foo: { 
     bar: { 
      quz: 'something' 
     } 
    } 
}; 

function setHierarchcally(obj, keys, value) { 
    if (!(obj && keys && keys.length)) return; 
    if (!obj.hasOwnProperty(keys[0])) return; 

    if (keys.length === 1) { 
     obj[keys[0]] = value; 
    } else { 
     setHierarchcally(obj[keys[0]], keys.slice(1, keys.length), value); 
    } 
} 


setHierarchcally(myObj, myArr, myVal); 
0

Если вы хотите более общий объект траверс, вы можете настроить JS-travserse немного, так как предназначалась в этом jsfiddle Я только что создал :

`https://jsfiddle.net/yxpx9wvL/10/ 


var leaves = new Traverse(myObj).reduce(function (acc, x) { 
if (this.isLeaf) acc.push(x); 
    return acc; 
}, []); 

alert(leaves[0]); 
+0

Пожалуйста, не публикуйте ответы, которые не содержат кода, а только ссылки на внешние страницы. Когда соединение ломается, ответ становится непригодным. И мы находимся на сайте программирования, код * принадлежит * в ответ. – Tomalak

0

getPath копается в объект, чтобы получить свойство на несколько уровней, основанное на массиве «путей», в вашем случае MyArr. Используйте это, чтобы получить объект, содержащий конечное свойство, а затем просто установите его.

function getPath(obj, paths) { 
    return paths.reduce(function(obj, path) { return obj[path]; }, obj); 
} 

function setLastProperty(obj, paths, val) { 
    var final = paths.pop(); 
    getPath(obj, paths) [ final ] = val; 
} 

setLastProperty(MyObj, MyArray, MyVal); 
Смежные вопросы