skip to content
usubeni fantasy logo Usubeni Fantasy

JavaScript 对象迭代方法与性能比较

/ 4 min read

原文地址:Iterating Over JavaScript Object Entries and their Performance - 5 Techniques

Object.entries

返回对象所有可枚举的键值对,不会追寻原型链上的 key

let obj = {
key1: "value1",
key2: "value2",
key3: "value3",
};
Object.entries(obj).forEach((entry) => {
let key = entry[0];
let value = entry[1];
// entry 会是这样 ["key1", "value1"]
});

Object.keys

返回对象所有可枚举的键

let obj = {
key1: "value1",
key2: "value2",
key3: "value3",
};
Object.keys(obj).forEach((key) => {
let value = obj[key];
});

Object.values

返回对象所有可枚举的值

let obj = {
key1: "value1",
key2: "value2",
key3: "value3",
};
Object.values(obj).forEach((value) => {
// 只能使用 value
});

for…in loop

迭代可枚举属性,会顺着原型链找下去

let obj = {
key1: "value1",
key2: "value2",
key3: "value3",
};
for (const key in obj) {
let value = obj[key];
if (obj.hasOwnProperty(key)) {
// 本身的
} else {
// 来自原型链的
}
}

Object.getOwnPropertyNames

返回对象所有(包括不可枚举)的键(原文说会找原型链是错的)

let obj = {
key1: "value1",
key2: "value2",
key3: "value3",
};
Object.getOwnPropertyNames(obj).forEach((key) => {
let value = obj[key];
});

性能比较

下面的代码用上面的几种方法遍历有 1000000 个属性的对象,循环 10 次

const { PerformanceObserver, performance } = require("perf_hooks");
let objectSize = 1000000;
let iterations = 10;
console.log(
"Starting performance test with %d object size and %d iterations",
objectSize,
iterations,
);
let values = {
ENTRIES: 0,
KEYS: 0,
VALUES: 0,
FORIN: 0,
GETOWP: 0,
};
const obs = new PerformanceObserver((items) => {
let entry = items.getEntries()[0];
console.log(entry.name, entry.duration);
values[entry.name] += entry.duration;
performance.clearMarks();
});
obs.observe({ entryTypes: ["measure"] });
function generateObject() {
let obj = {};
for (let i = 0; i < objectSize; i++) {
obj["key" + Math.random()] = "val" + Math.random();
}
return obj;
}
for (let i = 0; i < iterations; i++) {
let obj = generateObject();
//Object.entries
performance.mark("A");
Object.entries(obj).forEach((entry) => {
let key = entry[0];
let value = entry[1];
});
performance.mark("B");
performance.measure("ENTRIES", "A", "B");
//Object.Keys
performance.mark("A");
Object.keys(obj).forEach((key) => {
let value = obj[key];
});
performance.mark("B");
performance.measure("KEYS", "A", "B");
//Object.Values
performance.mark("A");
Object.values(obj).forEach((value) => {});
performance.mark("B");
performance.measure("VALUES", "A", "B");
//For In
performance.mark("A");
for (const key in obj) {
let value = obj[key];
}
performance.mark("B");
performance.measure("FORIN", "A", "B");
//Object.getOwnPropertyNames
performance.mark("A");
Object.getOwnPropertyNames(obj).forEach((key) => {
let value = obj[key];
});
performance.mark("B");
performance.measure("GETOWP", "A", "B");
}
console.log(
Object.entries(values).sort((a, b) => {
return a[1] - b[1];
}),
);

下面的结果是我自己跑的,顺序的是指赋值的时候直接用 index,随机则是键值对都插入随机数,得到的性能排序是和作者一样的,也因为 node.js 和 chrome 都是 V8,所以这个应该也是代表在浏览器上的性能排序。

// 顺序
[
["FORIN", 4677.321499],
["KEYS", 4812.776572],
["GETOWP", 8610.906197],
["VALUES", 9914.674390999999],
["ENTRIES", 19338.083694],
];
// 随机
[
["KEYS", 4502.579589],
["FORIN", 4678.013548000001],
["GETOWP", 8880.325031999999],
["VALUES", 10104.106962],
["ENTRIES", 17089.637588999998],
];

之前听说引擎会猜测下一个值让运行速度更快,看数据似乎没有太大影响。

也算是一点干货,快点来原文给作者鼓鼓掌吧 👏

评论组件加载中……