0

I have a situation where I need to zip two Objects together retaining both of the values. I can iterate through both the objects and build an array of all the keys.

    var traverse = function (obj, chain) {

        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {

                var tempChain = [].concat(chain || []);
                tempChain.push(prop);

                if (typeof obj[prop] === 'object') {
                    traverse(obj[prop], tempChain);
                }
                console.log(tempChain);
            }
        }
    };

Passing in the following:

    traverse({
        'a': {
            'b': 'hello world',
            'b1': 'hello world 1',
            'c': {
                'd': 'dello'
            }
        }
    })

Will return me:

[a]
[a,b]
[a,b1]
[a,c]
[a, c, d]

So I now have an array of nested properties in an object. How can I access essentially obj[[a,c,d]]? I know I can solve the problem through eval but I can't trust the content.

eval('window.' + ['a','c','d'].join('.')); 

If I can loop through that array and check to see if the property exists in both of them, then build a new object of the combined 'zipped' values.

dtsn
  • 1,077
  • 1
  • 10
  • 17
  • `window !== obj`, that wouldn't work anyway. But yes, you can use a simple loop. – Bergi Oct 04 '13 at 12:12
  • Check [any of these duplicates](http://stackoverflow.com/a/14397052/1048572) - just omit the `.split(".")` as you have an array already – Bergi Oct 04 '13 at 12:19
  • I think this is some kind of [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What exactly is your `zip` supposed to do, and why would you need property chains for that? – Bergi Oct 04 '13 at 14:35

1 Answers1

1

Perhaps something like this?

function getValueAt(obj, keyPathArray) {
    var emptyObj = {};

    return keyPathArray.reduce(function (o, key) {
        return (o || emptyObj)[key];
    }, obj);
}

Then you can use it like:

var o = { a: { c: { d: 1 } } };

getValueAt(o, ['a', 'c', 'd']); //1

However it's not efficient for non-existing properties, since it will not short-circuit. Here's another approach without using reduce:

function getValueAt(o, keyPathArray) {
    var i = 0, 
        len = keyPathArray.length;

    while (o != null && i < len) o = o[keyPathArray[i++]];

    return o;    
}
plalx
  • 42,889
  • 6
  • 74
  • 90
  • Why not simply `while (o!=null && i – Bergi Oct 04 '13 at 12:17
  • I've tried using both your solutions however the function returns the value and I want the object pointing to the value. To give a better explanation heres some working code which are using evals. http://jsbin.com/EHeFayu/7/ – dtsn Oct 04 '13 at 14:03
  • @Bergi, Yeah, somehow I haven't tought that the last value could be an object and that typeof `null` was 'object'. Silly mistakes. Fixed. – plalx Oct 04 '13 at 14:03
  • @dtsn, I cannot access jsbin right now, however I believe you could just ignore the last element in the array and it will return the object holding that property. `var keyPath = ['a', 'b', 'c']; keyPath = keyPath.slice(0, keyPath.length - 1); getValueAt(o, keyPath);` Obviously you have to hold a reference to the root object. – plalx Oct 04 '13 at 14:10