mapExploreDeep

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<table>
<tr><th>Source</th><th>Result</th></tr>
<tr><td>
<pre id="source"></pre>
</td><td>
<pre id="result"></pre>
</td></tr>
</table>

CSS

table{
  border-collapse: collapse;
}
td, th{
  border: 1px solid #666;
}

JavaScript

function mapExploreDeep(object, iterateeReplace, iterateeExplore = () => true) {
  return _.transform(object, (acc, value, key) => {
    const replaced = iterateeReplace(value, key, object);
    const explore = iterateeExplore(value, key, object);
    if (explore !== false && replaced !== null && typeof replaced === 'object') {
      acc[key] = mapExploreDeep(replaced, iterateeReplace, iterateeExplore);
    } else {
      acc[key] = replaced;
    }
    return acc;
  });
}

_.mixin({
  mapExploreDeep: mapExploreDeep,
});

const data = {
  one: 1,
  two: [{
    foo: 'bar',
  }, {
    foos: ['b', 'a', 'r', 's'],
  }, ],
  three: [1, 2, 3],
  safe: ['b', {
    baz: 'b',
  }],
};
$('#source').text(JSON.stringify(data, null, 4));
$('#result').text(JSON.stringify(_.mapExploreDeep(data, (val, key) => {
  if (typeof val === 'object') {
    return val;
  }
  return (String(val).indexOf('b') > -1) ? 'bobcat' : val;
}, (val, key) => key !== 'safe'), null, 4));