【问题标题】:How to deeply map object keys with JavaScript (lodash)?如何使用 JavaScript (lodash) 深度映射对象键?
【发布时间】:2016-05-05 11:43:56
【问题描述】:

https://lodash.com/docs#mapKeys

是否可以使用 Lodash 深度映射对象的键?如果没有,是否有另一个库提供此功能(如果与其他深度迭代和操作功能组合在一起,那就更好了!)?否则,将如何实现这一点?我看到的主要困难是识别安全、深度可迭代的纯键/值对象。丢弃数组很容易,但重要的是要注意该函数不应尝试深度迭代其他对象,例如正则表达式。

预期结果-

var obj = { a: 2, b: { c: 2, d: { a: 3 } } };
_.deepMapKeys(obj, function (val, key) {
  return key + '_hi';
});
// => { a_hi: 2, b_hi: { c_hi: 2, d_hi: { a_hi: 3 } } }

【问题讨论】:

    标签: javascript object key underscore.js lodash


    【解决方案1】:

    lodash 中您可以这样做:

    _.mixin({
        'deepMapKeys': function (obj, fn) {
    
            var x = {};
    
            _.forOwn(obj, function(v, k) {
                if(_.isPlainObject(v))
                    v = _.deepMapKeys(v, fn);
                x[fn(v, k)] = v;
            });
    
            return x;
        }
    });
    

    这是一个更抽象的 mixin,它递归地应用任何给定的映射器:

    _.mixin({
        deep: function (obj, mapper) {
            return mapper(_.mapValues(obj, function (v) {
                return _.isPlainObject(v) ? _.deep(v, mapper) : v;
            }));
        },
    });
    

    用法(返回同上):

    obj = _.deep(obj, function(x) {
        return _.mapKeys(x, function (val, key) {
            return key + '_hi';
        });
    });
    

    另一种选择,语法更优雅:

    _.mixin({
        deeply: function (map) {
            return function(obj, fn) {
                return map(_.mapValues(obj, function (v) {
                    return _.isPlainObject(v) ? _.deeply(map)(v, fn) : v;
                }), fn);
            }
        },
    });
    
    
    obj = _.deeply(_.mapKeys)(obj, function (val, key) {
        return key + '_hi';
    });
    

    【讨论】:

    • 这是一个很好的解决方案,所以我会支持它。但是,我发现在解决选项时接受的答案更简单,所以这是我推荐的方法。
    • @TejasManohar:嗯,你要求的代码是基于 lodash 的,并且能够区分普通对象和类型对象......接受的答案都不是。
    • 不错!我需要一个版本的deeply() 也可以深入到数组中。这是:gist.github.com/zambon/8b2d207bd21cf4fcd47b96cd6d7f99c2
    【解决方案2】:

    编辑:这将映射对象的值,而不是它的键。我误解了这个问题。


    function deepMap (obj, cb) {
        var out = {};
    
        Object.keys(obj).forEach(function (k) {
          var val;
    
          if (obj[k] !== null && typeof obj[k] === 'object') {
            val = deepMap(obj[k], cb);
          } else {
            val = cb(obj[k], k);
          }
    
          out[k] = val;
        });
    
      return out;
    }
    

    并将其用作

    var lol = deepMap(test, function (v, k) {
        return v + '_hi';
    });
    

    它将递归地遍历对象自身的可枚举属性,并调用一个 CB,将当前值和键传递给它。返回的值将替换新对象的现有值。它不会改变原始对象。

    见小提琴:https://jsfiddle.net/1veppve1/

    【讨论】:

    • 重要的是要注意,这会返回一个具有不同值的新对象,而不是问题中所问的键。也就是说,这是一个简单的更改,它表达了概念上的理解,所以我会保留一个反对票:)
    • @TejasManohar 该死的,对不起,我误解了重点。我以为您映射的是值而不是键。我会添加一个编辑,以免其他人感到困惑。
    • @alexanderElgin 我知道这需要付出努力,但你介意更新我的小提琴以展示一种减少冗余代码的方法吗?我并不是说听起来讽刺,我有兴趣提高我的知识和所有这些。
    【解决方案3】:

    在乔治的回答范围内,这就是我正在使用的。 这个扩展的 mixin 也增加了在对象中映射对象数组的能力,这是一个简单但重要的变化。

    _.mixin({
        deeply: function (map) {
          return function (obj, fn) {
            return map(_.mapValues(obj, function (v) {
              return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ? v.map(function(x) {
                return _.deeply(map)(x, fn);
              }) : v;
            }), fn);
          }
        },
      });
    

    【讨论】:

      【解决方案4】:

      我在Chris Jones's answer 基础上做了一个小改进。

      以下代码修复了 Array 元素的一些意外结果。

      _.mixin({
        deeply: function (map) {
          var deeplyArray = function (obj, fn) {
            return obj.map(function(x) {
              return _.isPlainObject(x) ? _.deeply(map)(x, fn) : x;
            })
          }
      
          return function (obj, fn) {
            if (_.isArray(obj)) {
              return deeplyArray(obj, fn);
            }
      
            return map(_.mapValues(obj, function (v) {
              return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ? 
                deeplyArray(v, fn) : v;
            }), fn);
          }
        },
      });
      

      【讨论】:

        【解决方案5】:

        就性能效率而言不是最好的,但是如果您想从您身边跳过递归部分并希望保持代码简洁明了,那么您可以将其字符串化为 json 并使用 JSON.parse 和附加参数(回调)在那里你可以用 lodash 转换键。

        JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v)
        

        这是一个工作示例:

        let obj = { a: 2, b: { c: 2, d: { a: 3 } } };
        let mappedObj = JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v)
        console.log(mappedObj)
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-31
          • 1970-01-01
          • 1970-01-01
          • 2017-02-08
          • 1970-01-01
          相关资源
          最近更新 更多