Set
[TOC]
索引
构造方法:
- new Set():
(iterable?)
,用于创建一个 Set 对象的构造函数。暂时没有字面量创建方式。
属性:
- set.size:
number
,只读,用于获取当前 Set 中元素的数量。
方法:
- set.add():
(value)
,修改原集合,用于向 Set 集合中添加新元素。遵循集合的唯一性原则,自动过滤重复值。 - set.delete():
(value)
,修改原集合,用于从集合中移除指定的元素。 - set.has():
(value)
,用于高效检查指定值是否存在于集合中。 - set.clear():
()
,修改原集合,用于一次性移除集合中的所有元素。 - set.forEach():
(callbackFn, thisArg?)
,允许对集合中的每个元素遍历执行指定操作。
Set
构造方法
new Set()@
new Set():(iterable?)
,用于创建一个 Set 对象的构造函数。暂时没有字面量创建方式。
iterable?:
Iterator
,可迭代对象,将其元素添加到 Set 中(重复值会被忽略)。返回:
set:
Set
,传入可迭代对象参数返回一个 Set 对象;没有参数则创建一个空 Set。
核心特性:
唯一性:所有值自动去重。
值重复判定严格:
5
和"5"
不同。NaN
等于自身(不同于===
)。对象引用不同则视为不同(即使内容相同):
jsconst obj = {a: 1}; const set = new Set([obj, {a: 1}]); console.log(set.size); // 2(两个不同对象)
顺序性:元素按插入顺序排列。
键与值相同:
Set
中的键和值相等(为兼容Map
设计)。jsconst set = new Set([10, 20, 30]); const entries = set.entries(); console.log([...entries]); // [[10, 10], [20, 20], [30, 30]]
遍历方法:
jsconst set = new Set([10, 20, 30]); // 1. 使用 forEach set.forEach(val => console.log(val)); // 10, 20, 30 // 2. 使用 for...of for (const val of set) { console.log(val); // 10, 20, 30 } // 3. 获取迭代器 const entries = set.entries(); console.log([...entries]); // [[10, 10], [20, 20], [30, 30]]
示例:
基础用法:
js// 1. 创建空 Set const emptySet = new Set(); console.log(emptySet); // Set(0) {} // 2. 从数组初始化(自动去重) const numSet = new Set([1, 2, 2, 3]); console.log(numSet); // Set(3) {1, 2, 3} // 3. 从字符串初始化(拆分字符) const charSet = new Set("hello"); console.log(charSet); // Set(4) {"h", "e", "l", "o"} // 4. 包含不同数据类型 const mixedSet = new Set([1, "1", {}, NaN, NaN]); console.log(mixedSet); // Set(4) {1, "1", {}, NaN}(NaN 被视为相同值)
应用场景:
数组去重:
jsconst arr = [1, 2, 2, 3]; const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
属性
size
set.size:number
,只读,用于获取当前 Set 中元素的数量。
核心特性:
实时反映:值会随
Set
内容变化自动更新。只读属性:不可直接修改(修改会被忽略)
jsconst set = new Set([1, 2]); set.size = 10; // 静默失败,size 仍为 2
高效计算:获取
size
的时间复杂度为O(1)
(直接读取内部计数)。对比 数组
length
:特性 Set.size Array.length 数据类型 数字(整数) 数字(整数) 可修改性 ❌ 只读 ✅ 可修改 空值表现 0 0 去重影响 仅计数唯一值 计数所有元素 稀疏处理 无稀疏概念 计数空位 ( [, ,]
)js// 对比示例 const arr = [1, , 3]; // 稀疏数组 console.log(arr.length); // 3(计数空位) const set = new Set([1, undefined, 3]); console.log(set.size); // 3(undefined 被视为有效值)
示例:
基础用法:
jsconst setA = new Set(['apple', 'banana']); console.log(setA.size); // 2
空 Set:
jsconst emptySet = new Set(); console.log(emptySet.size); // 0
动态更新:
jsconst dynamicSet = new Set(); console.log(dynamicSet.size); // 0 dynamicSet.add('a'); dynamicSet.add('b'); console.log(dynamicSet.size); // 2 dynamicSet.delete('a'); console.log(dynamicSet.size); // 1 dynamicSet.clear(); console.log(dynamicSet.size); // 0
自动去重影响:
jsconst dupSet = new Set([1, 1, 2, 2, 3]); console.log(dupSet.size); // 3(重复值被忽略)
方法
add()@
set.add():(value)
,修改原集合,用于向 Set 集合中添加新元素。遵循集合的唯一性原则,自动过滤重复值。
value:
any
,要添加到集合中的值,自动过滤重复值。返回:
set:
Set
,Set 对象本身(支持链式调用)。
核心特性:
支持链式调用:
jsconst set = new Set() .add('apple') .add('banana') .add('orange');
唯一性:所有值自动去重。
对象引用敏感:只匹配相同内存地址的对象。
jsconst obj1 = { id: 1 }; const obj2 = { id: 1 }; set.add(obj1); set.add(obj2); // 添加成功 console.log(set.size); // 2
值类型敏感:严格类型检查,不同类型但值相同的元素被区分。
jsset.add(5); // 数字 5 set.add("5"); // 字符串 "5" console.log(set.size); // 2
添加后集合可修改:
jsconst obj = { value: 10 }; const set = new Set().add(obj); obj.value = 20; // 修改已添加对象 console.log([...set][0].value); // 20
示例:
基本类型添加:
jsconst numberSet = new Set(); numberSet.add(1); numberSet.add(2).add(3); // 链式调用 console.log([...numberSet]); // [1, 2, 3]
重复值处理:
jsconst fruitSet = new Set(); fruitSet.add('🍎'); fruitSet.add('🍎'); // 被忽略 fruitSet.add('🍌'); console.log(fruitSet.size); // 2
混合类型:
jsconst mixedSet = new Set(); mixedSet.add(undefined); mixedSet.add(null); mixedSet.add(() => {}); mixedSet.add(Symbol('key')); console.log(mixedSet.size); // 4
动态添加对象:
jsconst userSet = new Set(); const user1 = { name: 'Alice' }; const user2 = { name: 'Bob' }; userSet.add(user1); userSet.add(user1); // 相同引用被忽略 userSet.add(user2); console.log(userSet.size); // 2
delete()
set.delete():(value)
,修改原集合,用于从集合中移除指定的元素。
value:
any
,要从集合中删除的值。返回:
isDeleted:
boolean
,返回是否删除成功。
核心特性:
精确匹配:
NaN
可以被删除(尽管NaN !== NaN
)。jsconst set = new Set([NaN]); console.log(set.delete(NaN)); // true
对象引用敏感:只匹配相同内存地址的对象。
值类型敏感:严格类型检查,不同类型但值相同的元素被区分。
不可链式调用:
delete()
返回布尔值而非 Set。js// 错误:delete() 返回布尔值而非 Set set.delete(1).delete(2); // TypeError
示例:
基本类型删除:
jsconst numberSet = new Set([1, 2, 3]); console.log(numberSet.delete(2)); // true console.log([...numberSet]); // [1, 3]
删除不存在的值:
jsconsole.log(numberSet.delete(5)); // false console.log(numberSet.size); // 2(集合未变化)
特殊值删除:可以删除
null
、NaN
和undefined
。jsconst specialSet = new Set([undefined, null, NaN]); console.log(specialSet.delete(null)); // true console.log(specialSet.delete(NaN)); // true console.log(specialSet.delete(undefined)); // true console.log([...specialSet]); // []
对象删除:需要删除对象的引用。
jsconst userSet = new Set(); const alice = { name: "Alice" }; const bob = { name: "Bob" }; userSet.add(alice).add(bob); console.log(userSet.delete(alice)); // true console.log([...userSet]); // [{name: "Bob"}
has()
set.has():(value)
,用于高效检查指定值是否存在于集合中。
value:
any
,要检查是否存在于集合中的值。返回:
has:
boolean
,返回是否存在指定值。
核心特性:
高效查询:时间复杂度为 O(1),远快于数组的
includes()
的 O(n)。jsconst largeSet = new Set([...Array(1000000).keys()]); const largeArray = [...largeSet]; console.time("Set.has"); largeSet.has(999999); // ~0.03ms console.timeEnd("Set.has"); console.time("Array.includes"); largeArray.includes(999999); // ~1500ms console.timeEnd("Array.includes");
精确匹配:可以正确识别
NaN
(尽管NaN !== NaN
)。对象引用敏感:只匹配相同内存地址的对象。
值类型敏感:严格类型检查,不同类型但值相同的元素被区分。
对比
map.has()
:set.has() 等价于 Map 的键检查js// Set 等价于 Map 的键检查 const set = new Set(["a"]); const map = new Map([["a", true]]); console.log(set.has("a") === map.has("a")); // true
示例:
基本类型检查:
jsconst colorSet = new Set(["red", "green", "blue"]); console.log(colorSet.has("green")); // true console.log(colorSet.has("yellow")); // false
特殊值检查:
jsconst specialSet = new Set([null, undefined, NaN]); console.log(specialSet.has(null)); // true console.log(specialSet.has(undefined)); // true console.log(specialSet.has(NaN)); // true
对象检查:
jsconst userSet = new Set(); const alice = { name: "Alice" }; userSet.add(alice); console.log(userSet.has(alice)); // true console.log(userSet.has({ name: "Alice" })); // false(不同对象)
动态变化检测:
jsconst dynamicSet = new Set([1, 2, 3]); console.log(dynamicSet.has(2)); // true dynamicSet.delete(2); // 删除元素 2 console.log(dynamicSet.has(2)); // false
clear()
set.clear():()
,修改原集合,用于一次性移除集合中的所有元素。
核心特性:
完全清空:移除集合中所有元素
原地操作:直接修改原集合,不创建新集合
高效执行:时间复杂度为 O(1)(直接重置内部数据结构)
引用保留:其他引用该集合的变量同步清空
jsconst setA = new Set([1, 2, 3]); const setB = setA; setA.clear(); console.log(setB.size); // 0(同步清空)
示例:
基础清空操作:
jsconst numberSet = new Set([1, 2, 3]); console.log(numberSet.size); // 3 numberSet.clear(); console.log(numberSet.size); // 0
空集合处理:
jsconst emptySet = new Set(); emptySet.clear(); // 无错误 console.log(emptySet.size); // 0
链式调用限制:
jsconst set = new Set([10, 20]); set.clear().add(30); // TypeError(clear() 返回 undefined)
forEach()@
set.forEach():(callbackFn, thisArg?)
,允许对集合中的每个元素遍历执行指定操作。
callbackFn:
(value?, key?, set?)=>void
,为集合中每个元素执行的函数。value?:
any
,当前处理的元素值(与 key 相同)。key?:
any
,当前处理的元素键(与 value 相同)。set?:
Set
,正在遍历的 Set 对象。
thisArg?:
any
,执行回调函数时用作 this 的值。返回:无
核心特性:
顺序保证:按照元素插入顺序遍历。
值键一致性:
value
和key
参数相同(为兼容 Map 设计)。只读遍历:遍历过程中修改集合会安全处理。
未调用新元素:只遍历调用 forEach 时存在的元素。
jsconst set = new Set([1]); set.forEach(v => { console.log(v); // 1 set.add(2); // 不会在此次遍历中处理 });
不可中断:无法像
for...of
那样使用break
js// 无法像 for...of 那样使用 break set.forEach(v => { if (v === 'stop') break; // SyntaxError }); // 替代方案:使用 for...of for (const v of set) { if (v === 'stop') break; }
同步执行:回调函数同步执行
jsconsole.log('Start'); set.forEach(v => console.log(v)); console.log('End'); // 输出顺序:Start → 元素 → End
空集合处理:无操作
jsnew Set().forEach(() => {}); // 无操作
示例:
基本遍历:
jsconst colorSet = new Set(['red', 'green', 'blue']); colorSet.forEach((value, key) => { console.log(`${key}: ${value}`); }); // 输出: // red: red // green: green // blue: blue
使用 thisArg:
jsconst colorSet = new Set(['red', 'green', 'blue']); class ColorLogger { log(value) { console.log(`Detected color: ${value}`); } } const logger = new ColorLogger(); colorSet.forEach(function(value) { this.log(value); // 2. this 指向 logger }, logger); // 1. 传入 this 指向的对象
修改集合(安全操作):只遍历调用 forEach 时存在的元素。
jsconst numberSet = new Set([1, 2, 3]); numberSet.forEach((v, _, set) => { if (v === 2) set.delete(1); // 安全删除 console.log(v); // 输出 1, 2, 3(删除不影响遍历) });
提前终止:无法直接终止,但可跳过剩余操作
jsconst numberSet = new Set([1, 2, 3]); let count = 0; numberSet.forEach(v => { if (count >= 2) return; // 无法直接终止,但可跳过剩余操作 console.log(v); count++; });