阿里云主机折上折
  • 微信号
Current Site:Index > Performance advantages of collection types

Performance advantages of collection types

Author:Chuan Chen 阅读数:54510人阅读 分类: JavaScript

ECMAScript 6 introduced two new collection types, Set and Map, which not only provide a more intuitive way to manipulate data structures but also significantly outperform traditional object and array implementations in terms of performance. These advantages become even more pronounced when handling large amounts of data.

Performance Advantages of the Set Type

Set is a collection that stores unique values. Its internal implementation is based on a hash table, making lookup, insertion, and deletion operations nearly O(1) in time complexity. In contrast, using array methods like includes or indexOf for lookups results in a time complexity of O(n).

Lookup Performance Comparison

const array = [1, 2, 3, 4, 5];
const set = new Set(array);

// Array lookup
console.time('Array includes');
console.log(array.includes(3)); // true
console.timeEnd('Array includes'); // ~0.1ms

// Set lookup
console.time('Set has');
console.log(set.has(3)); // true
console.timeEnd('Set has'); // ~0.01ms

When the data size increases to 10,000 elements, the performance advantage of Set becomes even more evident:

const largeArray = Array.from({ length: 10000 }, (_, i) => i);
const largeSet = new Set(largeArray);

// Array lookup for the last element
console.time('Large Array includes');
console.log(largeArray.includes(9999));
console.timeEnd('Large Array includes'); // ~0.5ms

// Set lookup for the same element
console.time('Large Set has');
console.log(largeSet.has(9999));
console.timeEnd('Large Set has'); // ~0.01ms

Deduplication Performance

Set inherently supports deduplication, whereas achieving the same with arrays requires additional logic:

const duplicateArray = [1, 2, 2, 3, 4, 4, 5];

// Array deduplication
const uniqueArray = [...new Set(duplicateArray)]; // [1, 2, 3, 4, 5]

This approach is more efficient than traditional array deduplication methods, such as using filter and indexOf:

// Traditional array deduplication
const traditionalUnique = duplicateArray.filter(
  (item, index) => duplicateArray.indexOf(item) === index
);

Performance Advantages of the Map Type

Map is a key-value pair collection. Unlike plain objects, its keys can be of any type (including objects), not just strings or Symbols. The time complexity for lookup, insertion, and deletion operations in Map is also O(1).

Lookup Performance Comparison

const obj = { key: 'value' };
const map = new Map([[key, 'value']]);

// Object lookup
console.time('Object property access');
console.log(obj.key); // 'value'
console.timeEnd('Object property access'); // ~0.05ms

// Map lookup
console.time('Map get');
console.log(map.get(key)); // 'value'
console.timeEnd('Map get'); // ~0.03ms

While the difference is negligible for small datasets, Map's performance advantage becomes more noticeable as the number of keys increases:

const largeObj = {};
const largeMap = new Map();

for (let i = 0; i < 10000; i++) {
  largeObj[i] = i;
  largeMap.set(i, i);
}

// Object lookup
console.time('Large Object property access');
console.log(largeObj[9999]); // 9999
console.timeEnd('Large Object property access'); // ~0.1ms

// Map lookup
console.time('Large Map get');
console.log(largeMap.get(9999)); // 9999
console.timeEnd('Large Map get'); // ~0.03ms

Flexibility in Key Types

Map allows objects to be used as keys, which is not possible with plain objects:

const objKey1 = { id: 1 };
const objKey2 = { id: 2 };

const map = new Map();
map.set(objKey1, 'value1');
map.set(objKey2, 'value2');

console.log(map.get(objKey1)); // 'value1'

Iteration Performance

Map provides more efficient iteration methods, allowing direct traversal with for...of:

const map = new Map([
  ['key1', 'value1'],
  ['key2', 'value2'],
]);

for (const [key, value] of map) {
  console.log(key, value);
}

In contrast, iterating over an object's key-value pairs requires additional steps:

const obj = { key1: 'value1', key2: 'value2' };

for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key, obj[key]);
  }
}

Memory Advantages of WeakSet and WeakMap

WeakSet and WeakMap are variants of Set and Map that hold weak references to their keys, meaning they do not prevent garbage collection. This is particularly useful for memory management:

let obj = { data: 'important' };
const weakSet = new WeakSet();
weakSet.add(obj);

// When obj is no longer referenced, the entry in weakSet is automatically cleared
obj = null;

A typical use case for WeakMap is storing private data:

const privateData = new WeakMap();

class MyClass {
  constructor() {
    privateData.set(this, { secret: 42 });
  }

  getSecret() {
    return privateData.get(this).secret;
  }
}

const instance = new MyClass();
console.log(instance.getSecret()); // 42

Practical Applications

Using Set for Efficient Set Operations

const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);

// Union
const union = new Set([...setA, ...setB]); // Set {1, 2, 3, 4, 5}

// Intersection
const intersection = new Set([...setA].filter(x => setB.has(x))); // Set {3}

// Difference
const difference = new Set([...setA].filter(x => !setB.has(x))); // Set {1, 2}

Using Map to Implement an LRU Cache

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.map = new Map();
  }

  get(key) {
    if (!this.map.has(key)) return -1;
    const value = this.map.get(key);
    this.map.delete(key);
    this.map.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.map.has(key)) this.map.delete(key);
    this.map.set(key, value);
    if (this.map.size > this.capacity) {
      this.map.delete(this.map.keys().next().value);
    }
  }
}

Browser Compatibility and Transpilation

While modern browsers support ES6 collection types, older browsers may require polyfills:

// Using core-js polyfills
import 'core-js/features/set';
import 'core-js/features/map';

For Babel users, necessary transpilation can be handled automatically via @babel/preset-env:

// babel.config.js
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 3,
      },
    ],
  ],
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:常用集合操作

下一篇:实际应用场景

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.