如何使用 JavaScript (lodash) 深度映射对象键?

Posted

技术标签:

【中文标题】如何使用 JavaScript (lodash) 深度映射对象键?【英文标题】:How to deeply map object keys with 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   

【问题讨论】:

【参考方案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>

【讨论】:

以上是关于如何使用 JavaScript (lodash) 深度映射对象键?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Javascript/Lodash/ES6 中同时搜索父对象和子对象?

如何在 HTML 中使用来自 lodash/fp 的管道?

JavaScript工具库——Lodash.js介绍安装及使用

如何使用 Lodash.js 对集合/数组进行反透视?

如何在使用 lodash 省略空值的同时合并两个对象

javascript 两个对象之间的深度差异,使用lodash