ES6 - 集合
ES6+ - 现代集合:Map, Set, WeakMap, WeakSet
Section titled “ES6+ - 现代集合:Map, Set, WeakMap, WeakSet”ES6 引入了强大的新型内置数据结构:Map、Set、WeakMap 和 WeakSet。与传统的对象 (object) 和数组 (array) 相比,它们提供了更灵活的方式来组织和管理数据集合。
Map 对象保存键/值对 (key-value pairs),并记住键的原始插入顺序。任何值(包括对象和原始值 primitive value)都可以用作键或值。这相较于普通对象是一个显著优势,因为普通对象的键会被隐式转换为字符串。
语法:`new Map([iterable])`其中 `iterable` 是一个数组 (`Array`) 或其他可迭代对象 (`iterable object`),其元素是键值对(包含两个元素的数组,如 `[key, value]`)。Map 的主要属性和方法:
Section titled “Map 的主要属性和方法:”map.size:返回Map中的键/值对数量。map.set(key, value):添加或更新指定键和值的元素。返回Map对象,允许链式调用 (chaining)。map.get(key):返回与键关联的值,如果找不到键则返回undefined。map.has(key):返回一个布尔值,指示是否存在指定键的元素。map.delete(key):移除具有指定键的元素。如果元素存在并被移除,则返回true,否则返回false。map.clear():移除Map对象中的所有键/值对。
迭代方法(都返回迭代器 Iterator):
Section titled “迭代方法(都返回迭代器 Iterator):”map.keys():返回一个新的迭代器对象,该对象包含Map中按插入顺序排列的所有键。map.values():返回一个新的迭代器对象,该对象包含Map中按插入顺序排列的所有值。map.entries():返回一个新的迭代器对象,该对象包含Map中按插入顺序排列的每个元素的[key, value]数组。这是 Map 的默认迭代器 (default iterator)。
map.forEach(callbackFn[, thisArg]):按插入顺序对 Map 中的每个键值对执行一次 callbackFn(回调函数)。
示例:Map 的基本操作
Section titled “示例:Map 的基本操作”const userRoles = new Map();
// Set key-value pairsuserRoles.set('admin', 'Administrator Access');userRoles.set('editor', 'Content Editor Access');userRoles.set(123, 'Numeric Key Example'); // Keys can be non-strings
const user = { id: 1 };userRoles.set(user, 'Object Key Example'); // Keys can be objects
console.log(userRoles.get('admin')); // Output: Administrator Accessconsole.log(userRoles.get(user)); // Output: Object Key Exampleconsole.log(userRoles.has('guest')); // Output: falseconsole.log(userRoles.size); // Output: 4
// Initialize with an array of key-value pairsconst settings = new Map([ ['theme', 'dark'], ['fontSize', 16]]);console.log(settings.get('theme')); // Output: dark
// Iterating over a Map using for...of (default is entries)for (const [key, value] of userRoles) { console.log(`${typeof key} ${key}: ${value}`);}// Example output for one entry: string admin: Administrator Access
// Iterating using forEachsettings.forEach((value, key) => { console.log(`Setting - ${key}: ${value}`);});// Output:// Setting - theme: dark// Setting - fontSize: 16WeakMap
Section titled “WeakMap”WeakMap 是一个键/值对的集合,其中的键必须是对象,值可以是任意类型。对键的引用是“弱引用” (weakly) 的,这意味着如果没有其他引用指向某个键对象,该对象就可以被垃圾回收 (garbage collected),并且它在 WeakMap 中的对应条目也会被自动移除。这使得 WeakMap 非常适合将数据与对象关联起来,而不会阻止这些对象被垃圾回收。
WeakMap 的主要特点:
- 键必须是对象。不允许使用原始值作为键。
- 条目不可枚举 (
enumerable)。你不能迭代遍历WeakMap(没有keys()、values()、entries()、forEach()或size属性)。 - 只有
get(key)、set(key, value)、has(key)和delete(key)方法可用。
示例:使用 WeakMap
Section titled “示例:使用 WeakMap”let activeUsers = new WeakMap();
let user1 = { name: 'Alice' };let user2 = { name: 'Bob' };
activeUsers.set(user1, { lastLogin: Date.now() });activeUsers.set(user2, { status: 'online' });
console.log(activeUsers.has(user1)); // Output: trueconsole.log(activeUsers.get(user1)); // Output: { lastLogin: ... }
// If user1 becomes eligible for garbage collection (e.g., user1 = null and no other references exist),// its entry in activeUsers will eventually be removed by the garbage collector.user1 = null;// At some point, activeUsers.has(the_original_user1_object) would be false.Set 对象允许你存储任何类型的唯一值,无论是原始值还是对象引用 (object references)。Set 中的值按照插入顺序排列。
语法:`new Set([iterable])`其中 `iterable` 是一个数组 (`Array`) 或其他可迭代对象,其元素用于初始化集合。Set 的主要属性和方法:
Section titled “Set 的主要属性和方法:”set.size:返回Set中唯一值的数量。set.add(value):将value添加到Set。返回Set对象(可链式调用)。如果value已存在,则不做任何更改。set.has(value):返回一个布尔值,指示是否存在具有指定值的元素。set.delete(value):从Set中移除指定的值。如果值找到并被移除,则返回true,否则返回false。set.clear():移除Set对象中的所有元素。
迭代方法(都返回迭代器):
Section titled “迭代方法(都返回迭代器):”set.values():返回一个新的迭代器对象,该对象包含Set中按插入顺序排列的所有值。这是 Set 的默认迭代器。set.keys():是values()的别名,行为完全相同。set.entries():返回一个新的迭代器对象,该对象包含Set中按插入顺序排列的每个元素的[value, value]数组(为了与Map保持一致)。
set.forEach(callbackFn[, thisArg]):按插入顺序对 Set 中的每个值执行一次 callbackFn。回调函数接收 (value, key, set),其中 key 与 value 相同。
示例:Set 的基本操作
Section titled “示例:Set 的基本操作”const uniqueNumbers = new Set([1, 2, 2, 3, 4, 4, 4]);
console.log(uniqueNumbers.size); // Output: 4 (duplicates are ignored)
uniqueNumbers.add(5);uniqueNumbers.add(1); // Already exists, no changeconsole.log(uniqueNumbers.has(3)); // Output: true
uniqueNumbers.delete(2);console.log(uniqueNumbers.has(2)); // Output: false
// Iterating over a Set using for...of (default is values)for (const number of uniqueNumbers) { console.log(number);}// Output (in insertion order, e.g.): 1, 3, 4, 5
// Iterating using forEachuniqueNumbers.forEach(value => { console.log(`Set value: ${value}`);});WeakSet
Section titled “WeakSet”WeakSet 仅存储对象。类似于 WeakMap,对 WeakSet 中对象的引用是“弱引用”的。如果 WeakSet 中的对象没有其他引用指向它,它就可以被垃圾回收。
WeakSet 的主要特点:
- 只能存储对象。不允许使用原始值。
- 条目不可枚举。你不能迭代遍历
WeakSet(没有迭代器、forEach或size)。 - 只有
add(value)、has(value)和delete(value)方法可用。
示例:使用 WeakSet
Section titled “示例:使用 WeakSet”let processedObjects = new WeakSet();
let obj1 = { id: 'A' };let obj2 = { id: 'B' };
function processObject(obj) { if (!processedObjects.has(obj)) { console.log(`Processing object: ${obj.id}`); // ... perform processing ... processedObjects.add(obj); } else { console.log(`Object ${obj.id} already processed.`); }}
processObject(obj1);processObject(obj2);processObject(obj1); // Will indicate it's already processed
// If obj1 becomes eligible for GC, its entry in processedObjects is removed.obj1 = null;集合中的迭代器
Section titled “集合中的迭代器”ES6+ 中的所有标准集合(Array、Map、Set、String)都是可迭代的 (iterable)。这意味着它们实现了迭代器协议 (iterator protocol)。迭代器 (iterator) 是一个知道如何一次访问集合中一个项目,并跟踪其在序列中当前位置的对象。迭代器有一个 next() 方法,该方法返回一个具有两个属性的对象:value(序列中的下一个项目)和 done(一个布尔值,如果迭代器已到达序列末尾则为 true)。
示例:手动迭代
Section titled “示例:手动迭代”const myMap = new Map([['a', 1], ['b', 2]]);const mapIterator = myMap.entries(); // Get an iterator
console.log(mapIterator.next()); // { value: ['a', 1], done: false }console.log(mapIterator.next()); // { value: ['b', 2], done: false }console.log(mapIterator.next()); // { value: undefined, done: true }
const mySet = new Set(['apple', 'banana']);const setIterator = mySet.values();
console.log(setIterator.next()); // { value: 'apple', done: false }console.log(setIterator.next()); // { value: 'banana', done: false }console.log(setIterator.next()); // { value: undefined, done: true }虽然手动迭代是可能的,但 for...of 循环是处理可迭代对象最常见和最方便的方式。