A better way to trim all elements in an object recursively?

江枫思渺然 提交于 2020-06-27 18:48:11

问题


If I have an object like,

const obj = {
    field: {
        subfield: {
            innerObj: { a: ' asdasd  asdas . ' },
            innerArr: ['  s  ', '  ssad . '],
            innerArrObj: [ { b: '   adsad  ' } ],
        }
    }
}

I've come up with something like this,

const trimFields = (data) =>
  _.mapValues(data, (element, k) =>
    _.isArray(element)
      ? element.map((value) =>
          _.isObject(value) ? trimFields(value) : trimText(value)
        )
      : _.isObject(element)
      ? trimFields(element)
      : trimText(element)
  );

But I'm wondering if there is a better / more efficient way to do this?

JSFiddle


回答1:


I'd switch for array / object / other directly in the function, simplifying the recursive call:

 const trimFields = (data) =>
    _.isArray(data) 
      ? data.map(trimFields)
      :  _.isObject(data) 
        ? _.mapValues(trimFields)
        : trimText(data);



回答2:


I would write a more general deepMap function and then call it with trimText and your object. It then becomes easily reusable, and it separates out the handling of object navigation from your actual field transformation. It's not hard to write, either with or without lodash. Here's one version:

const deepMap = (fn) => (obj) => 
  Array .isArray (obj) 
    ? obj .map (deepMap (fn))
  : Object (obj) === obj
    ? Object .fromEntries (Object .entries (obj) .map (([k, v]) => [k, deepMap (fn) (v)]))
  : // else 
    fn (obj)

const trimText = field => typeof field === 'string' ? field .trim () : field;

const obj = {field: {subfield: {innerObj: { a: ' asdasd  asdas . ' }, innerArr: ['  s  ', '  ssad . '], innerArrObj: [ { b: '   adsad  ' } ]}}}

console .log (
  deepMap (trimText) (obj)
)

Note that I simplified trimText, since trim is built into String.prototype.

Writing this generic version is pretty much no more difficult than a one-off version, and you can reuse it for other purposes.

deepMap (square) ({a: 1, b: [2, 3, 4], c: [{d: 5}, {d: 6}]})
//=> {a: 1, b: [4, 9, 16], c: [{d: 25}, {d: 36}]}



回答3:


The lodash's _.transform() function iterates both objects and arrays. You can create a recursive mapValues() function using _.transform(), and then apply a transformer function (_.trim() in this case) to handle all values:

const recursiveMapValues = _.curry((fn, obj) => 
  _.transform(obj, (acc, value, key) => {
      acc[key] = _.isObject(value) ?
        recursiveMapValues(fn, value)
        :
        fn(value)
  }))
  
const trimFields = recursiveMapValues(v => _.isString(v) ? _.trim(v) : v)

const obj = {"field":{"subfield":{"innerObj":{"a":" asdasd  asdas . "},"innerArr":["  s  ","  ssad . ", 3],"innerArrObj":[{"b":"   adsad  "}]}}}

const result = trimFields(obj)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>


来源:https://stackoverflow.com/questions/61098396/a-better-way-to-trim-all-elements-in-an-object-recursively

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!