有没有一种使用underscore.js重命名js对象键的方法?

66

我需要将一个JavaScript对象转换为另一个对象,以便在向服务器发送POST请求时使用。但是需要注意的是,目标对象的键名与原对象不同。

var a = {
    name : "Foo",
    amount: 55,
    reported : false,
    ...
    <snip/>
    ...
    date : "10/01/2001"
    } 

需要转换为

a = {
  id : "Foo",
  total : 55,
  updated: false,
  ...
  <snip/>
  ... 
  issued : "10/01/2001"
  }

我有一个lookup对象可用于映射所有键

var serverKeyMap = {
    name : "id",
    amount : "total",
    reported : "updated",
     ...
    date : "issue"
    }
有没有在underscore.js或jQuery中可用的函数,我可以使用来实现这个功能?
谢谢。

8
不是下划线(underscore),而是 Lodash 提供了 _.mapKeys 方法来修改对象的键。 - CookieEater
16个回答

76

我知道你没有提及lodash,而且回答已经解决了问题,但其他人可能会从替代方案中受益。

如评论中@CookieMonster所提到的,您可以使用_.mapKeys来实现此目的:

_.mapKeys(a, function(value, key) {
    return serverKeyMap[key];
});

而且这里还有一个小提琴:http://jsfiddle.net/cwkwtgr3/


5
这个有很强的副作用。 - DFlores009
@DFlores009 像什么?那样会更有帮助。 - coler-j

42

与 @pimvdb 类似,您也可以使用 _.reduce 来实现:

_.reduce(a, function(result, value, key) {
    key = map[key] || key;
    result[key] = value;
    return result;
}, {});

Fiddle: http://jsfiddle.net/T9Lnr/39/


似乎对我仍然有效@wegginho,它会打印到控制台。 - dule
我遇到了一个错误,提示下划线未定义。 - bastianwegge
1
下划线作为外部资源附加,也许它所在的位置被阻止了?尝试打开文件以查看是否可以访问。 - dule

38
据我所知,这两个库中都没有内置的函数。不过,你可以很容易地自己制作一个:http://jsfiddle.net/T9Lnr/1/
var b = {};

_.each(a, function(value, key) {
    key = map[key] || key;
    b[key] = value;
});

11

您可以使用标准JavaScript将值复制到新属性中,并使用omit删除原始属性,如下所示:

a.id = a.name;
a.total = a.amount;
a.updated = a.reported;
a = _.omit(a, 'name', 'amount', 'reported');

请添加一些解释。目前,您的答案被标记为“低质量”,可能会被删除。 - Johannes Jander
使用此方法无法更改具有多个值的所有键。 - Faris Rayhan

3
// key_map: {old_name1: new_name1, ... }
function rename_keys(object, key_map, is_picked=false){
  keys = _.keys(key_map);
  new_keys = _.values(key_map);
  picked = _.pick(object, keys);
  renamed = _.object(new_keys, _.values(picked));
  if(is_picked) return renamed;

  return _.chain(object).omit(keys).extend(renamed).value();
}

这可能比上面的答案慢。

2

很抱歉,这两个库中都没有明确重命名键的函数。您的方法也是最快的(请参见jsperf测试)。如果可能的话,最好重构客户端或服务器端代码,使对象相同。


1
基准测试中的测试用例甚至看起来都不相等。 - meandre

2

这里已经解决了 https://dev59.com/V4zda4cB1Zd3GeqPiij0#30940370

var keyMapping = {'PropertyA': 'propertyA', ..., 'PropertyF': 'propertyNEW'}

同时还需要一个旧值和新值的映射关系,如下所示:
var valueMapping = {'Y': true, 'F': false}

然后使用 _.map 和 _.transform,您可以像这样转换对象。
var result = _.map(allItems, function(currentObject) {
    return _.transform(currentObject, function(result, value, key) {
        if (key === 'PropertyF' || key === 'PropertyG') {
            value = valueMapping(value);
        }
        result[keyMapping[key]] = value;
    });
});

2
为什么不使用这个简单的JavaScript?任何键值对的值都应该是字符串/数字/布尔类型。
<script type="text/javascript">    
    var serverKeyMap = {
        name : "id",
        amount : "total",
        reported : "updated"
    };

    var a = {
        name : "Foo",
        amount: 55,
        reported : false
    };

    var b={}; // b is object where you will get your output

    for(i in serverKeyMap) b[serverKeyMap[i]]=a[i];

    console.log(b); // It gives what you need.

</script>

2

我有一个转换操作符,希望将其应用于所有键。我fork了pimvdb的小例子来展示这个简单的示例。在这种情况下,它将键名大写,并动态构建键映射表,以确保其正常工作(感谢JSFiddle)。

以下是修改后的代码:

var keymap = {};
_.each(a, function(value, key) {
    var oldkey = key;
    key = capitalize(key);
    keymap[oldkey] = key;
});
_.each(a, function(value, key) {
    key = keymap[key] || key;
    b[key] = value;
});

Fiddle: http://jsfiddle.net/mr23/VdNjf/


虽然这个例子是人为制造的,但在实际生活中,我使用它来构建一个“清理”键映射,使用数据集的第一条记录,并将其应用于其余部分(可能包括额外的数据加载)。 - sw.chef
我最终使用了上面的_.replace()解决方案,但一开始我看了你的解决方案和plunkr。效果很好,谢谢。 - FireDragon

1

现在,你真的不需要使用underscore/lodash了...(我知道这个问题是9年前提出的,但是这个问题在搜索结果中排名很高,今天我偶然发现它 :-))

这里有另一个我喜欢的纯ES2015/2017版本,受@malbarmavi答案的启发(可能还有很多其他纯JS函数,但在我的简短搜索中没有找到其他函数):

// A general key transform method. Pass it a function that accepts the old key and returns
// the new key.
//
// @example
//   obj = transformKeys(obj, (key) => (
//    key.replace(/\b(big)\b/g, 'little')
//  ))
export function transformKeys(source, f) {
  return Object.entries(source).reduce((o, [key, value]) => {
    o[f(key) || key] = value
    return o
  }, {})
}
 
// Provide an object that maps from old key to new key
export function rekeyObject(source, keyMap) {
  transformKeys(source, key => keyMap[key])
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接