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)
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)
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,因此现在您可以在对象和数组表示形式之间来回切换。
loDash/fp方式,非常好,因为它基本上是一个衬垫
import {
mapKeys
} from 'lodash/fp'
export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
Run Code Online (Sandbox Code Playgroud)
在我的测试中使用 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)
ES6版本:
Object.keys(source)
.reduce((destination, key) => {
destination[key.toLowerCase()] = source[key];
return destination;
}, {});
Run Code Online (Sandbox Code Playgroud)