Javascript 将对象的所有键转换为小写的最佳方式(最有效)是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12539574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best way (most efficient) to turn all the keys of an object to lower case?
提问by Jo?o Pinto Jerónimo
I've come up with
我想出了
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);
}
But I'm not sure how will v8 behave with that, for instance, will it really delete the other keys or will it only delete references and the garbage collector will bite me later ?
但是我不确定 v8 会如何处理,例如,它会真的删除其他键还是只会删除引用并且垃圾收集器稍后会咬我?
Also, I created these tests, I'm hoping you could add your answer there so we could see how they match up.
另外,我创建了这些测试,我希望你可以在那里添加你的答案,这样我们就可以看到它们是如何匹配的。
EDIT 1:Apparently, according to the tests, it's faster if we don't check if the key is already in lower case, but being faster aside, will it create more clutter by ignoring this and just creating new lower case keys ? Will the garbage collector be happy with this ?
编辑 1:显然,根据测试,如果我们不检查密钥是否已经是小写字母,速度会更快,但是如果不检查,是否会因为忽略这一点而仅创建新的小写字母键而造成更多混乱?垃圾收集器会对此感到满意吗?
采纳答案by some
The fastestI come up with is if you create a new object:
我想出的最快的方法是创建一个新对象:
var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
key = keys[n];
newobj[key.toLowerCase()] = obj[key];
}
I'm not familiar enough with the current inner working of v8 to give you a definitive answer. A few years ago I saw a video where the developers talked about objects, and IIRC it will only delete the references and let the garbage collector take care of it. But it was years ago so even if it was like that then, it doesn't need to be like that now.
我对 v8 当前的内部工作不够熟悉,无法给你一个明确的答案。几年前我看到一个视频,开发人员谈论对象,而 IIRC 只会删除引用并让垃圾收集器处理它。不过那是几年前的事了,就算那时候是那样,现在也不必那样了。
Will it bite you later? It depends on what you are doing, but probably not. It is very common to create short lived objects so the code is optimized to handle it. But every environment has its limitations, and maybe it will bite you. You have to test with actual data.
以后会咬你吗?这取决于你在做什么,但可能不是。创建短期对象是很常见的,因此代码被优化以处理它。但每个环境都有其局限性,也许它会咬你。您必须使用实际数据进行测试。
回答by caleb
I'd use Lo-Dash.transformlike this:
我会像这样使用Lo-Dash.transform:
var lowerObj = _.transform(obj, function (result, val, key) {
result[key.toLowerCase()] = val;
});
回答by Molomby
Personally, I'd use:
就个人而言,我会使用:
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;
}, {});
}
It's succinct, recurs to handle nested objects and returns a new object rather than modifying the original.
它简洁,递归处理嵌套对象并返回一个新对象而不是修改原始对象。
In my limited local testing this function is faster than the other recursive solution currently listed (once fixed). I'd love to benchmark it against the others but jsperf is down at the moment (???).
在我有限的本地测试中,此函数比当前列出的其他递归解决方案(一旦修复)更快。我很想将它与其他人进行基准测试,但目前 jsperf 已关闭 (???)。
It's also written in ES5.1 so, according to the docs on MDN, should work in FF 4+, Chrome 5+, IE 9.0+, Opera 12+, Safari 5+ (so, pretty much everything).
它也是用 ES5.1 编写的,因此,根据 MDN 上的文档,它应该适用于 FF 4+、Chrome 5+、IE 9.0+、Opera 12+、Safari 5+(所以,几乎所有的东西)。
Vanilla JS for the win.
Vanilla JS 获胜。
I wouldn't worry too much about the garbage collection aspect of all this. Once all references to the old object are destroyed it will be GC's but the newobject will still reference basically all it's properties, so they will not.
我不会太担心这一切的垃圾收集方面。一旦对旧对象的所有引用都被销毁,它将是 GC,但新对象基本上仍将引用它的所有属性,因此它们不会。
Any Functions, Arrays or RegExp will be "copied" across by reference. In terms of memory, even Strings will not be duplicated by this process since most (all?) modern JS engines user string interning. I think that leaves just the Numbers, Booleans and the Objects that formed the original structure left to be GC'd.
任何函数、数组或正则表达式都将通过引用“复制”。在内存方面,即使字符串也不会被这个过程复制,因为大多数(全部?)现代 JS 引擎用户字符串实习。我认为只剩下构成原始结构的数字、布尔值和对象需要 GC 处理。
Note that (all implementations of) this process will lose values if the original has multiple properties with the same lowercase representation. Ie:
请注意,如果原始文件具有多个具有相同小写表示的属性,则此过程(的所有实现)将丢失值。IE:
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!' }
Of course, sometimes this is exactly what you want.
当然,有时这正是您想要的。
Update 2018-07-17
更新 2018-07-17
A few people have noted the original function doesn't work well with arrays. Here's an expanded, more resilient version. It recurs correctly through arrays and works if the initial value is an array or simple value:
一些人注意到原始函数不适用于数组。这是一个扩展的、更具弹性的版本。如果初始值是数组或简单值,它会通过数组正确递归并工作:
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;
}, {});
};
回答by Yves M.
Using Object.fromEntries
(ES10)
使用Object.fromEntries
(ES10)
Native and immutable solution using the new Object.fromEntries
method:
使用新Object.fromEntries
方法的本机和不可变解决方案:
const newObj = Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);
Until that function becomes widely availableyou could define it yourself with the following polyfill:
在该功能广泛可用之前,您可以使用以下polyfill自己定义它:
Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));
A nice thing is that this method does the opposite of Object.entries
, so now you can go back and forth between the object and array representation.
一件好事是,此方法与 执行相反的操作Object.entries
,因此现在您可以在对象和数组表示之间来回切换。
回答by Damian Green
The loDash/fp way, quite nice as its essentially a one liner
loDash/fp 方式,非常好,因为它本质上是一个单衬
import {
mapKeys
} from 'lodash/fp'
export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
回答by Tom Roggero
ES6 version:
ES6版本:
Object.keys(source)
.reduce((destination, key) => {
destination[key.toLowerCase()] = source[key];
return destination;
}, {});
回答by kennebec
Using forEach seems to be a bit quicker in my tests- and the original reference is gone, so deleting the new one will put it in reach of the g.c.
在我的测试中使用 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);
}
var O={ONE:1,two:2,tHree:3,FOUR:4,Five:5,SIX:{a:1,b:2,c:3,D:4,E:5}}; keysToLowerCase(O);
var O={一:1,二:2,三:3,四:4,五:5,六:{a:1,b:2,c:3,D:4,E:5}}; keysToLowerCase(O);
/* returned value: (Object) */
/* 返回值:(对象)*/
{
five:5,
four:4,
one:1,
six:{
a:1,
b:2,
c:3,
D:4,
E:5
},
three:3,
two:2
}
回答by El.
I used ES6 and TypeScript.
toLowerCaseObject
function takes an Array as parameter and looking through Object tree recursively and make every node lowercase:
我使用了 ES6 和 TypeScript。
toLowerCaseObject
函数接受一个数组作为参数并递归地查看对象树并使每个节点小写:
function toLowerCaseObject(items: any[]) {
return items.map(x => {
let lowerCasedObject = {}
for (let i in x) {
if (x.hasOwnProperty(i)) {
lowerCased[i.toLowerCase()] = x[i] instanceof Array ? toLowerCaseObject(x[i]) : x[i];
}
}
return lowerCasedObject;
});
}
回答by Grant Miller
Simplified Answer
简化答案
For simple situations, you can use the following example to convert all keys to lower case:
对于简单的情况,您可以使用以下示例将所有键转换为小写:
Object.keys(example).forEach(key => {
const value = example[key];
delete example[key];
example[key.toLowerCase()] = value;
});
You can convert all of the keys to upper case using toUpperCase()
instead of toLowerCase()
:
您可以使用toUpperCase()
而不是将所有键转换为大写toLowerCase()
:
Object.keys(example).forEach(key => {
const value = example[key];
delete example[key];
example[key.toUpperCase()] = value;
});
回答by Dave Sag
This is how I do it. My input can be anything and it recuses through nested objects as well as arrays of objects.
我就是这样做的。我的输入可以是任何东西,它通过嵌套对象以及对象数组回避。
const fixKeys = input => Array.isArray(input)
? input.map(fixKeys)
: typeof input === 'object'
? Object.keys(input).reduce((acc, elem) => {
acc[elem.toLowerCase()] = fixKeys(input[elem])
return acc
}, {})
: input
tested using mocha
使用 mocha 测试
const { expect } = require('chai')
const fixKeys = require('../../../src/utils/fixKeys')
describe('utils/fixKeys', () => {
const original = {
Some: 'data',
With: {
Nested: 'data'
},
And: [
'an',
'array',
'of',
'strings'
],
AsWellAs: [
{ An: 'array of objects' }
]
}
const expected = {
some: 'data',
with: {
nested: 'data'
},
and: [
'an',
'array',
'of',
'strings'
],
aswellas: [{ an: 'array of objects' }]
}
let result
before(() => {
result = fixKeys(original)
})
it('left the original untouched', () => {
expect(original).not.to.deep.equal(expected)
})
it('fixed the keys', () => {
expect(result).to.deep.equal(expected)
})
})