admin管理员组

文章数量:1279118

What's the best way to search through a JavaScript object of unknown depth and properties and replace all instances of given string?

This works, but is it the best way?

var obj = {
   'a' : 'The fooman poured the drinks.',
   'b' : {
      'c' : 'Dogs say fook, but what does the fox say?'
   }
}

console.log (JSON.parse(JSON.stringify(obj).replace(/foo/g, 'bar')));

Fiddle: /

What's the best way to search through a JavaScript object of unknown depth and properties and replace all instances of given string?

This works, but is it the best way?

var obj = {
   'a' : 'The fooman poured the drinks.',
   'b' : {
      'c' : 'Dogs say fook, but what does the fox say?'
   }
}

console.log (JSON.parse(JSON.stringify(obj).replace(/foo/g, 'bar')));

Fiddle: http://jsfiddle/93Uf4/3/

Share Improve this question asked Apr 13, 2014 at 19:13 Andrew DownesAndrew Downes 5577 silver badges13 bronze badges 6
  • 1 I would do it the same way as you do. – bobthedeveloper Commented Apr 13, 2014 at 19:22
  • 3 Do you want it to apply to both keys and values? Can the object contain functions? – Ingo Bürk Commented Apr 13, 2014 at 19:23
  • 3 Using this method to replace :, ', ", { or any such thing is likely to cause a plete meltdown. I'd write a function that does this using recursion. – mzedeler Commented Apr 13, 2014 at 19:31
  • Also, using the regex /some string$/ won't behave the way most people would expect. – mzedeler Commented Apr 13, 2014 at 19:32
  • In my particular case, just values but the keys will never contain the search term. The object does not contain functions. – Andrew Downes Commented Apr 13, 2014 at 21:11
 |  Show 1 more ment

1 Answer 1

Reset to default 9

Next to the way you proposed yourself, here is a classic loop approach. As mentioned by someone in a ment, it's more stable because you don't risk screwing the object up and throwing an error when trying to parse it back. On the other hand, some questions arise (see bottom).

Be careful, though, as the needle will be used as a regular expression. You may want to consider adding some sort of quoting to it.

I hope I didn't overlook anything, so test it and play around with it. Here you can find a fiddle.

/**
  * Replaces all occurrences of needle (interpreted as a regular expression with replacement and returns the new object.
  * 
  * @param entity The object on which the replacements should be applied to
  * @param needle The search phrase (as a regular expression)
  * @param replacement Replacement value
  * @param affectsKeys[optional=true] Whether keys should be replaced
  * @param affectsValues[optional=true] Whether values should be replaced
  */
Object.replaceAll = function (entity, needle, replacement, affectsKeys, affectsValues) {
    affectsKeys = typeof affectsKeys === "undefined" ? true : affectsKeys;
    affectsValues = typeof affectsValues === "undefined" ? true : affectsValues;

    var newEntity = {},
        regExp = new RegExp( needle, 'g' );
    for( var property in entity ) {
        if( !entity.hasOwnProperty( property ) ) {
            continue;
        }

        var value = entity[property],
            newProperty = property;

        if( affectsKeys ) {
            newProperty = property.replace( regExp, replacement );
        }

        if( affectsValues ) {
            if( typeof value === "object" ) {
                value = Object.replaceAll( value, needle, replacement, affectsKeys, affectsValues );
            } else if( typeof value === "string" ) {
                value = value.replace( regExp, replacement );
            }
        }

        newEntity[newProperty] = value;
    }

    return newEntity;
};

The last two parameters are optional, so it's perfectly fine to just call it like this:

var replaced = Object.replaceAll( { fooman: "The dog is fooking" }, "foo", "bar" );

However, there are still edge cases where it's unclear what should happen. For example:

// do you expect it to stay undefined or change type and bee "undebazed"?
console.log( Object.replaceAll( { x: undefined }, "fin", "baz" ) );

// null or "nalala"?
console.log( Object.replaceAll( { x: null }, "ull", "alala" ) );

Or

// true or false?
console.log( Object.replaceAll( { x: true }, "true", "false" ) );

// true or "foo"?
console.log( Object.replaceAll( { x: true }, "true", "foo" ) );

And the same for numbers

// 1337 or 1007?
console.log( Object.replaceAll( { x: 1337 }, "33", "00" ) );

// 1337 or "1foo7"
console.log( Object.replaceAll( { x: 1337 }, "33", "foo" ) );

None of these cases are currently handled in my method – only objects (for nesting) and strings will be touched.

本文标签: Replace all instances of a string within an object (andor array)JavaScriptStack Overflow