javascript for-in vs Object.keys forEach 没有继承的属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25052758/
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
for-in vs Object.keys forEach without inherited properties
提问by majidarif
I was looking at a perf benchmark of Object.keys
+ forEach
vs for-in
with normal objects.
我一直在寻找的PERF基准Object.keys
+ forEach
VSfor-in
正常的对象。
Thisbenchmark shows that Object.keys
+ forEach
is 62% slowerthan the for-in
approach. But what if you don't want to get the inherited properties? for-in
includes all non-native inherited objects, so we'll have to use hasOwnPropertyto check.
这个基准显示,Object.keys
+forEach
是慢62%比for-in
的方法。但是如果您不想获得继承的属性怎么办?for-in
包括所有非本地继承的对象,所以我们必须使用hasOwnProperty来检查。
I tried to make another benchmark heredoing exactly that. But now the for-in
approach is 41% slowerthan Object.keys
+ forEach
.
我试图在这里做另一个基准测试。但现在这种for-in
方法比+慢 41%。Object.keys
forEach
update
更新
The above test was done in Chrome. Tested it again but with Safari and I'm getting different results: Object.keys(..).forEach(..) 34% slower
, odd.
上面的测试是在 Chrome 中完成的。再次测试,但使用 Safari,我得到了不同的结果:Object.keys(..).forEach(..) 34% slower
,奇怪。
Note: The reason I'm benchmarking is to check how it is with Node.js.
注意:我进行基准测试的原因是检查Node.js 的情况。
Questions:
问题:
- Are the
jsperf
result for Chromeconsiderable for Node.js? - What happened, how come a single conditional made the
for-in
approach 41% slowerthanObject.keys
+forEach
in Chrome?
- Chrome的
jsperf
结果对于Node.js 来说是否可观? - 发生了什么,为什么在Chrome 中,单个条件使该
for-in
方法比+慢 41%?Object.keys
forEach
回答by MaxArt
node.js uses V8, although I guess it's not the same as the current version in Chrome, but I guess it's a good indicator of node's performances on the subject.
node.js 使用 V8,虽然我猜它与 Chrome 中的当前版本不同,但我猜它是 node 在该主题上的表现的一个很好的指标。
Secondarily, you're using forEach
, which is quite handy when developing but adds a callback for every iteration, and that's a (relatively) lenghty task. So, if you're interested in performances, why don't you just use a normal for
loop?
其次,您正在使用forEach
,这在开发时非常方便,但会为每次迭代添加回调,这是一项(相对)冗长的任务。所以,如果您对表演感兴趣,为什么不使用普通for
循环呢?
for (var i = 0, keys = Object.keys(object); i < keys.length; i++) {
// ...
}
This yields the best performances you can get, solving your speed problems in Safari too.
这会产生您可以获得的最佳性能,也可以解决您在 Safari 中的速度问题。
In short: it's not the conditional, it's the call to hasOwnProperty
that makes a difference. You're doing a function call at every iteration, so that's why for...in
becomes slower.
简而言之:这不是条件,而是调用hasOwnProperty
会产生影响。你在每次迭代时都在做一个函数调用,所以这就是for...in
变慢的原因。
回答by Jean Robert
Just to note that:
只是要注意:
var keys = Object.keys(obj), i = keys.length;
while(--i) {
//
}
will not run for the index 0 and then you'll miss one of your attributes.
不会为索引 0 运行,然后您将错过您的属性之一。
This in an array like ["a","b","c","d"] will run only d,c,b, and you'll miss the "a" 'cause index is 0 and 0 is false.
这在像 ["a","b","c","d"] 这样的数组中只会运行 d,c,b,你会错过 "a",因为索引是 0 而 0 是假的。
You need to decrement after the while check:
您需要在 while 检查后递减:
var keys = Object.keys(obj), i = keys.length;
while(i--) {
//
}
回答by baetheus
I was interested in this today as well, but mostly because I don't like having to test with hasOwnProperty to pass the default lint when I already know my objects are clean (as they've been created from object literals). Anyway, I expanded a little on the answer by @styonsk to include a better output and to run multiple tests and return the output.
我今天也对此感兴趣,但主要是因为当我已经知道我的对象是干净的(因为它们是从对象文字创建的)时,我不喜欢使用 hasOwnProperty 进行测试以传递默认的 lint。无论如何,我对@styonsk 的答案进行了一些扩展,以包含更好的输出并运行多个测试并返回输出。
Conclusion:It's complicated for node. The best time looks like using Object.keys() with either a numerical for loop or a while loop on nodejs v4.6.1. On v4.6.1, the forIn loop with hasOwnProperty is the slowest method. However, on node v6.9.1 it is the fastest, but it is still slower than both Object.keys() iterators on v4.6.1.
结论:node 很复杂。最好的时间看起来是在 nodejs v4.6.1 上使用带有数字 for 循环或 while 循环的 Object.keys()。在 v4.6.1 上,带有 hasOwnProperty 的 forIn 循环是最慢的方法。然而,在节点 v6.9.1 上它是最快的,但它仍然比 v4.6.1 上的两个 Object.keys() 迭代器慢。
Notes:This was run on a late 2013 MacBook Pro with 16GB ram and a 2.4Ghz i5 processor. Every test pegged 100% of a single cpu for the duration of the test and had an average rss of about 500MB and peaked at 1GB of rss. Hope this helps someone.
注意:这是在 2013 年末的 MacBook Pro 上运行的,配备 16GB 内存和 2.4Ghz i5 处理器。在测试期间,每个测试都与单个 CPU 的 100% 挂钩,平均 rss 约为 500MB,峰值为 1GB。希望这可以帮助某人。
Here are my results running against nodejs v6.9.1 and v4.6.1 with large objects (10^6 properties) and small objects(50 properties)
这是我针对具有大对象(10^6 个属性)和小对象(50 个属性)的 nodejs v6.9.1 和 v4.6.1 运行的结果
Node v4.6.1 with large object 10^6 properties
testObjKeyWhileDecrement Test Count:100 Total Time:57595 ms Average Time:575.95 ms
testObjKeyForLoop Test Count:100 Total Time:54885 ms Average Time:548.85 ms
testForInLoop Test Count:100 Total Time:86448 ms Average Time:864.48 ms
Node v4.6.1 with small object 50 properties
testObjKeyWhileDecrement Test Count:1000 Total Time:4 ms Average Time:0.004 ms
testObjKeyForLoop Test Count:1000 Total Time:4 ms Average Time:0.004 ms
testForInLoop Test Count:1000 Total Time:14 ms Average Time:0.014 ms
Node v6.9.1 with large object 10^6 properties
testObjKeyWhileDecrement Test Count:100 Total Time:94252 ms Average Time:942.52 ms
testObjKeyForLoop Test Count:100 Total Time:92342 ms Average Time:923.42 ms
testForInLoop Test Count:100 Total Time:72981 ms Average Time:729.81 ms
Node v4.6.1 with small object 50 properties
testObjKeyWhileDecrement Test Count:1000 Total Time:8 ms Average Time:0.008 ms
testObjKeyForLoop Test Count:1000 Total Time:10 ms Average Time:0.01 ms
testForInLoop Test Count:1000 Total Time:13 ms Average Time:0.013 ms
具有大对象 10^6 属性的 Node v4.6.1
testObjKeyWhileDecrement 测试计数:100 总时间:57595 毫秒 平均时间:575.95 毫秒
testObjKeyForLoop 测试计数:100 总时间:54885 毫秒 平均时间:548.85 毫秒
testForInLoop 测试计数:100 总时间:86448 毫秒平均时间:864.48 毫秒
Node v4.6.1 小对象50个属性
testObjKeyWhileDecrement 测试计数:1000 总时间:4 毫秒 平均时间:0.004 毫秒
testObjKeyForLoop 测试计数:1000 总时间:4 毫秒 平均时间:0.004 毫秒
testForInLoop 测试计数:1000 总时间:14 毫秒 平均时间:0.014 毫秒
具有大对象 10^6 属性的 Node v6.9.1
testObjKeyWhileDecrement 测试计数:100 总时间:94252 毫秒 平均时间:942.52 毫秒
testObjKeyForLoop 测试计数:100 总时间:92342 毫秒 平均时间:923.42 毫秒
testForInLoop 测试计数:100 总时间:72981 毫秒 平均时间:729.81 毫秒
Node v4.6.1 小对象50个属性
testObjKeyWhileDecrement 测试计数:1000 总时间:8 毫秒 平均时间:0.008 毫秒
testObjKeyForLoop 测试计数:1000 总时间:10 毫秒 平均时间:0.01 毫秒
testForInLoop 测试计数:1000 总时间:13 毫秒 平均时间:0.013 毫秒
And following is the code I ran:
以下是我运行的代码:
//Helper functions
function work(value) {
//do some work on this value
}
function createTestObj(count) {
var obj = {}
while (count--) {
obj["key" + count] = "test";
}
return obj;
}
function runOnce(func, obj) {
var start = Date.now();
func(obj);
return Date.now() - start;
}
function testTimer(name, func, obj, count) {
count = count || 100;
var times = [];
var i = count;
var total;
var avg;
while (i--) {
times.push(runOnce(func, obj));
}
total = times.reduce(function (a, b) { return a + b });
avg = total / count;
console.log(name);
console.log('Test Count: ' + count);
console.log('Total Time: ' + total);
console.log('Average Time: ' + avg);
console.log('');
}
//Tests
function testObjKeyWhileDecrement(obj) {
var keys = Object.keys(obj);
var i = keys.length;
while (i--) {
work(obj[keys[i]]);
}
}
function testObjKeyForLoop(obj) {
var keys = Object.keys(obj);
var len = keys.length;
var i;
for (i = 0; i < len; i++) {
work(obj[keys[i]]);
}
}
function testForInLoop(obj) {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
work(obj[key]);
}
}
}
//Run the Tests
var data = createTestObj(50)
testTimer('testObjKeyWhileDecrement', testObjKeyWhileDecrement, data, 1000);
testTimer('testObjKeyForLoop', testObjKeyForLoop, data, 1000);
testTimer('testForInLoop', testForInLoop, data, 1000);
回答by coldfire
For anyone viewing still concerned with iterating object properties in JS, the absolute fastest method is:
对于仍然关注在 JS 中迭代对象属性的任何人来说,绝对最快的方法是:
var keys = Object.keys(obj), i = keys.length;
while(--i) {
//
}
http://jsperf.com/object-keys-foreach-vs-for-in-hasownproperty/8
http://jsperf.com/object-keys-foreach-vs-for-in-hasownproperty/8
You can save a bit on large objects by not having to recompute the length value of the key array (mostly negligible with modern browser optimizations), which is also true for the case of a simple for loop. The decremented while loop is still faster than the for loop or the incremented while loop with length upper limit comparison, by a fair margin.
通过不必重新计算键数组的长度值(在现代浏览器优化中几乎可以忽略不计),您可以在大对象上节省一点,这对于简单的 for 循环也是如此。递减的 while 循环仍然比 for 循环或具有长度上限比较的递增的 while 循环快,幅度相当大。
回答by styonsk
I tested this today. For my purposes, getting the Object keys and then doing a plain old for loop was faster than doing a decrementing while or a for in loop. Feel free to change this template to test the different loops out for your individual case:
我今天测试了这个。就我而言,获取对象键然后执行普通的旧 for 循环比执行递减 while 或 for in 循环要快。随意更改此模板以针对您的个人情况测试不同的循环:
//Helper functions
function work(value) {
//do some work on this value
}
function createTestObj(count) {
var obj = {}
while (count--) {
obj["key" + count] = "test";
}
return obj;
}
//Tests
function test_ObjKeyWhileDecrement(obj) {
console.log("Time Started: ", new Date().getTime());
var keys = Object.keys(obj),
i = keys.length;
while (i--) {
work(obj[keys[i]]);
}
console.log("Time Finished: ", new Date().getTime());
}
function test_ObjKeyForLoop(obj) {
console.log("Time Started: ", new Date().getTime());
for (var i = 0, keys = Object.keys(obj); i < keys.length; i++) {
work(obj[keys[i]]);
}
console.log("Time Finished: ", new Date().getTime());
}
function test_ForInLoop(obj) {
console.log("Time Started: ", new Date().getTime());
for (key in obj) {
work(obj[key]);
}
console.log("Time Finished: ", new Date().getTime());
}
//Run the Tests
var data = createTestObj(1000 * 100)
console.log("Test Obj Key While Decrement Loop")
test_ObjKeyWhileDecrement(data);
console.log("Test Obj Key For Loop")
test_ObjKeyForLoop(data);
console.log("Test For In Loop")
test_ForInLoop(data);
You may want to run that in your actual environment to test instead of in a jsfiddle. Try multiple browsers also.
您可能希望在实际环境中运行它以进行测试,而不是在 jsfiddle 中运行。也尝试多个浏览器。
回答by Dallas
And for the ES6 fans out there, looks like
对于那里的 ES6 粉丝来说,看起来像
Object.keys(obj).reduce((a,k) => {a += obj[k]; return a}, res)
is by far the fastest.
是迄今为止最快的。