views:

154

answers:

4
+2  Q: 

too much recursion

Hey guys, I got an error in javascript and it won't get away. :-) In the little recursive thingy following, I want to replace a value inside a (nested) object.

var testobj = {
    'user': {
        'name': 'Mario',
        'password': 'itseme'
    }
};

updateObject('emesti', 'password', testobj)

function updateObject(_value, _property, _object) {
    for(var property in _object) {
        if(property == _property) {
            _object[property] = _value;
        }
        else if(objectSize(_object) > 0) {
            updateObject(_value, _property, _object[property]);
        }
    }

    return _object
};

function objectSize(_object) {
    var size = 0, key;
    for (key in _object) {
        if (_object.hasOwnProperty(key)) size++;
    }
    return size;
};

After running this, firefox throws the exception "too much recursion" on the line else if(objectSize(_object) > 0) { .

Edit: if I set

function updateObject(_value, _property, _object) {
    for(var property in _object) {
        if(property == _property) {
            _object[property] = _value;
        }
        else if(_object[property].hasOwnProperty(_property)) {
            updateObject(_value, _property, _object[property]);
        }
    }

    return _object
};

it works, but it only searches one level. If I had an nested object inside a nested object, it wouldn't work.

Any more ideas? (Thanks for the effort so far)

Edit: This problem occurs in Firefox 3.6. It works in Chrome.

+4  A: 

I'm not 100% familiar with how to do things in Javascript, but essentially you want something like this:

var testobj = {
    'user': {
        'name': 'Mario',
        'password': 'itseme',
        'bleh': {
            'password': 'something'
        }
    }
};

function updateObject(_value, _property, _object) {
    for(var property in _object) {
        if(property == _property) {
            _object[property] = _value;
        }
        else if(explorable(_object[property])) {
            updateObject(_value, _property, _object[property]);
        }
    }

    return _object
};

function explorable(_object) {
    return typeof(_object) != "string";
};

updateObject('emesti', 'password', testobj);
document.writeln(testobj.user.password);      // "emesti"
document.writeln(testobj.user.bleh.password); // "emesti"

Currently, anything that isn't a string is explorable. This may or may not work for all cases, so you may want to use a better definition of what is explorable.

Also note that the recursion right now updates ALL matching properties.

polygenelubricants
I've been looking at this one for about half an hour :-D thanks a lot, but sadly this wasn't the "final" solution.
Dänu
@Dänu: check latest revision.
polygenelubricants
Dänu
Your solution works perfect, thanks!
Dänu
btw the javascript types (as return by typeof()) are 'string', 'number' and 'boolean'. At least, those are the ones I tested, I guess there should at least be one for array as well.
Dänu
ok javascript types: string, number, boolean, object, function, null and undefined. Oh what a hickhack
Dänu
For great comedy effect, typeof used with both arrays and null returns "object", even though the first is accurate-if-unhelpful, and the latter is just wrong. Just something to watch out for.
Matt Sach
+1  A: 

shouldn't if(objectSize(_object) > 0) { be if(objectSize(_object[property]) > 0) {?

x1a4
+1  A: 

You're not using .hasOwnProperty() in the for loop inside updateObject. Could it be finding some kind of in-built property which is essentially "infinite" in depth?

Matt Sach
Hey Matt, I think the Object can't have any other properties than the ones you set. Else we couldn't use them as associative arrays ...
Dänu
Oh ho ho, @Dänu, but yes an Object definitely **can** have other properties, inherited from its prototype. That's why the `hasOwnProperty` function exists!
Pointy
A: 

Here's an idea:

function updateObject(_value, _property, _object) {
    function u(v, p, o) {
      if (o === _object) return;
      if (o.hasOwnProperty(p))
        o[p] = v;
      else {
        for (var prop in o)
          if (o.hasOwnProperty(prop))
            u(v, p, o[prop]);
      }
    }
    u(_value, _property, _object);
    return _object
};

That adds a test to make sure you don't start over back at the original object.

Pointy