将对象的所有键变为小写的最佳方法(最有效)是什么?

Joã*_*imo 59 javascript performance garbage-collection object node.js

我想出来了

function keysToLowerCase (obj) {
  var keys = Object.keys(obj);
  var n = keys.length;
  while (n--) {
    var key = keys[n]; // "cache" it, for less lookups to the array
    if (key !== key.toLowerCase()) { // might already be in its lower case version
        obj[key.toLowerCase()] = obj[key] // swap the value to a new lower case key
        delete obj[key] // delete the old key
    }
  }
  return (obj);
}
Run Code Online (Sandbox Code Playgroud)

但我不确定v8将如何表现,例如,它是否真的会删除其他键,还是只会删除引用,垃圾收集器会在以后咬我?

另外,我创建了这些测试,我希望你能在那里添加你的答案,这样我们就能看出它们是如何匹配的.

编辑1: 显然,根据测试,如果我们不检查密钥是否已经是小写,但是速度更快,它会更快,它是否会通过忽略这个而只是创建新的小写密钥来创建更多的混乱?垃圾收集者会对此感到满意吗?

som*_*ome 61

我提出的最快的是你创建一个新对象:

var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
  key = keys[n];
  newobj[key.toLowerCase()] = obj[key];
}
Run Code Online (Sandbox Code Playgroud)

我对v8目前的内部工作不够熟悉,无法给你一个明确的答案.几年前,我看到一个开发人员谈论对象的视频,而IIRC只会删除引用并让垃圾收集器处理它.但它是几年前所以即使它就像那样,它现在也不需要那样.

以后会咬你吗?这取决于你在做什么,但可能不是.创建短期对象非常常见,因此代码已经过优化以处理它.但每个环境都有其局限性,也许它会咬你.您必须使用实际数据进行测试.

2017年更新:

添加了一个实用程序函数,可以生成对象的浅或深副本,支持循环引用.仅在节点上进行了简单测试

var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
  key = keys[n];
  newobj[key.toLowerCase()] = obj[key];
}
Run Code Online (Sandbox Code Playgroud)


cal*_*leb 29

我会像这样使用Lo-Dash.transform:

var lowerObj = _.transform(obj, function (result, val, key) {
    result[key.toLowerCase()] = val;
});
Run Code Online (Sandbox Code Playgroud)

  • 您现在可以使用 [`Object.fromEntries`](/sf/answers/3848983911/) 来实现相同类型的转换,但本机使用原生 JavaScript (3认同)

Mol*_*mby 24

就个人而言,我会用:

let objectKeysToLowerCase = function (origObj) {
    return Object.keys(origObj).reduce(function (newObj, key) {
        let val = origObj[key];
        let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
}
Run Code Online (Sandbox Code Playgroud)

它简洁,重复处理嵌套对象并返回一个新对象而不是修改原始对象.

在我有限的本地测试中,此功能比当前列出的其他递归解决方案(一旦修复)更快.我喜欢将它与其他人进行对比,但jsperf此刻正在下降(???).

它也是用ES5.1编写的,因此,根据MDN上的文档,它应该适用于FF 4 +,Chrome 5 +,IE 9.0 +,Opera 12 +,Safari 5+(所以,几乎所有内容).

香草JS获胜.

我不会太担心这一切的垃圾收集方面.一旦对旧对象的所有引用都被销毁,它将是GC,但对象仍将基本上引用它的所有属性,因此它们不会.

任何函数,数组或RegExp都将通过引用"复制".在内存方面,即使字符串也不会被这个过程复制,因为大多数(所有?)现代JS引擎用户字符串实习.我认为只留下数字,布尔和形成原始结构的对象留下GC.

请注意,如果原始文件具有多个具有相同小写表示的属性,则此过程的所有实现都将丢失值.即:

let myObj = { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' };
console.log(myObj);
// { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' }

let newObj = objectKeysToLowerCase(myObj);
console.log(newObj);
// { xx: 'one!' }
Run Code Online (Sandbox Code Playgroud)

当然,有时这正是你想要的.

更新2018-07-17

一些人已经注意到原始功能与数组不兼容.这是一个扩展的,更具弹性的版本.它通过数组正确地重复,并且如果初始值是数组或简单值,则可以正常工作:

let objectKeysToLowerCase = function (input) {
    if (typeof input !== 'object') return input;
    if (Array.isArray(input)) return input.map(objectKeysToLowerCase);
    return Object.keys(input).reduce(function (newObj, key) {
        let val = input[key];
        let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
};
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用您的解决方案,但它不适用于值= null 的属性。我已将 `if (typeof input !== 'object') return input;` 修改为 `if (typeof input !== 'object' || input===null) return input;` (2认同)

Yve*_* M. 7

使用Object.fromEntries(ES.next)

使用新Object.fromEntries方法的原生且不变的解决方案:


const newObj = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);
Run Code Online (Sandbox Code Playgroud)

在该功能广泛可用之前,您可以使用以下ES.next polyfill自己定义它:

Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));
Run Code Online (Sandbox Code Playgroud)

一件好事是,该方法的作用与之相反Object.entries,因此现在您可以在对象和数组表示形式之间来回切换。


Dam*_*een 6

loDash/fp方式,非常好,因为它基本上是一个衬垫

import {
mapKeys
} from 'lodash/fp'

export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
Run Code Online (Sandbox Code Playgroud)


ken*_*bec 5

在我的测试中使用 forEach 似乎要快一些 - 并且原始参考已经消失,因此删除新参考将使 gc 可以使用它

function keysToLowerCase(obj){
    Object.keys(obj).forEach(function (key) {
        var k = key.toLowerCase();

        if (k !== key) {
            obj[k] = obj[key];
            delete obj[key];
        }
    });
    return (obj);
}
Run Code Online (Sandbox Code Playgroud)

var O={一:1,二:2,三:3,四:4,五:5,六:{a:1,b:2,c:3,D:4,E:5}}; keysToLowerCase(O);

/* 返回值:(对象)*/

{
    five:5,
    four:4,
    one:1,
    six:{
        a:1,
        b:2,
        c:3,
        D:4,
        E:5
    },
    three:3,
    two:2
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*ero 5

ES6版本:

Object.keys(source)
  .reduce((destination, key) => {
    destination[key.toLowerCase()] = source[key];
    return destination;
  }, {});
Run Code Online (Sandbox Code Playgroud)