Skip to content

Set

[TOC]

索引

构造方法

  • new Set()(iterable?),用于创建一个 Set 对象的构造函数。暂时没有字面量创建方式

属性

  • set.sizenumber只读,用于获取当前 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。

核心特性

  1. 唯一性:所有值自动去重。

    • 值重复判定严格:5"5" 不同。

    • NaN 等于自身(不同于 ===)。

    • 对象引用不同则视为不同(即使内容相同):

      js
      const obj = {a: 1};
      const set = new Set([obj, {a: 1}]);
      console.log(set.size); // 2(两个不同对象)
  2. 顺序性:元素按插入顺序排列。

  3. 键与值相同Set 中的键和值相等(为兼容 Map 设计)。

    js
    const set = new Set([10, 20, 30]);
    const entries = set.entries();
    console.log([...entries]); // [[10, 10], [20, 20], [30, 30]]
  4. 遍历方法

    js
    const 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]]

示例

  1. 基础用法

    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 被视为相同值)

应用场景

  1. 数组去重

    js
    const arr = [1, 2, 2, 3];
    const uniqueArr = [...new Set(arr)]; // [1, 2, 3]

属性

size

set.sizenumber只读,用于获取当前 Set 中元素的数量

核心特性

  1. 实时反映:值会随 Set 内容变化自动更新。

  2. 只读属性:不可直接修改(修改会被忽略)

    js
    const set = new Set([1, 2]);
    set.size = 10; // 静默失败,size 仍为 2
  3. 高效计算:获取 size 的时间复杂度为 O(1)(直接读取内部计数)。

  4. 对比 数组 length

    特性Set.sizeArray.length
    数据类型数字(整数)数字(整数)
    可修改性❌ 只读✅ 可修改
    空值表现00
    去重影响仅计数唯一值计数所有元素
    稀疏处理无稀疏概念计数空位 ([, ,])
    js
    // 对比示例
    const arr = [1, , 3]; // 稀疏数组
    console.log(arr.length); // 3(计数空位)
    
    const set = new Set([1, undefined, 3]);
    console.log(set.size); // 3(undefined 被视为有效值)

示例

  1. 基础用法

    js
    const setA = new Set(['apple', 'banana']);
    console.log(setA.size); // 2
  2. 空 Set

    js
    const emptySet = new Set();
    console.log(emptySet.size); // 0
  3. 动态更新

    js
    const 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
  4. 自动去重影响

    js
    const dupSet = new Set([1, 1, 2, 2, 3]);
    console.log(dupSet.size); // 3(重复值被忽略)

方法

add()@

set.add()(value)修改原集合,用于向 Set 集合中添加新元素。遵循集合的唯一性原则,自动过滤重复值。

  • valueany,要添加到集合中的值,自动过滤重复值。

  • 返回:

  • setSet,Set 对象本身(支持链式调用)。

核心特性

  1. 支持链式调用

    js
    const set = new Set()
      .add('apple')
      .add('banana')
      .add('orange');
  2. 唯一性:所有值自动去重。

  3. 对象引用敏感:只匹配相同内存地址的对象。

    js
    const obj1 = { id: 1 };
    const obj2 = { id: 1 };
    
    set.add(obj1);
    set.add(obj2); // 添加成功
    console.log(set.size); // 2
  4. 值类型敏感:严格类型检查,不同类型但值相同的元素被区分。

    js
    set.add(5);      // 数字 5
    set.add("5");    // 字符串 "5"
    console.log(set.size); // 2
  5. 添加后集合可修改

    js
    const obj = { value: 10 };
    const set = new Set().add(obj);
    
    obj.value = 20; // 修改已添加对象
    console.log([...set][0].value); // 20

示例

  1. 基本类型添加

    js
    const numberSet = new Set();
    numberSet.add(1);
    numberSet.add(2).add(3); // 链式调用
    console.log([...numberSet]); // [1, 2, 3]
  2. 重复值处理

    js
    const fruitSet = new Set();
    fruitSet.add('🍎');
    fruitSet.add('🍎'); // 被忽略
    fruitSet.add('🍌');
    console.log(fruitSet.size); // 2
  3. 混合类型

    js
    const mixedSet = new Set();
    mixedSet.add(undefined);
    mixedSet.add(null);
    mixedSet.add(() => {});
    mixedSet.add(Symbol('key'));
    console.log(mixedSet.size); // 4
  4. 动态添加对象

    js
    const 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)修改原集合,用于从集合中移除指定的元素

  • valueany,要从集合中删除的值。

  • 返回:

  • isDeletedboolean,返回是否删除成功。

核心特性

  1. 精确匹配NaN 可以被删除(尽管 NaN !== NaN)。

    js
    const set = new Set([NaN]);
    console.log(set.delete(NaN)); // true
  2. 对象引用敏感:只匹配相同内存地址的对象。

  3. 值类型敏感:严格类型检查,不同类型但值相同的元素被区分。

  4. 不可链式调用delete() 返回布尔值而非 Set。

    js
    // 错误:delete() 返回布尔值而非 Set
    set.delete(1).delete(2); // TypeError

示例

  1. 基本类型删除

    js
    const numberSet = new Set([1, 2, 3]);
    console.log(numberSet.delete(2)); // true
    console.log([...numberSet]);     // [1, 3]
  2. 删除不存在的值

    js
    console.log(numberSet.delete(5)); // false
    console.log(numberSet.size);      // 2(集合未变化)
  3. 特殊值删除:可以删除 nullNaNundefined

    js
    const 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]);          // []
  4. 对象删除:需要删除对象的引用。

    js
    const 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),用于高效检查指定值是否存在于集合中

  • valueany,要检查是否存在于集合中的值。

  • 返回:

  • hasboolean,返回是否存在指定值。

核心特性

  1. 高效查询:时间复杂度为 O(1),远快于数组的 includes() 的 O(n)。

    js
    const 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");
  2. 精确匹配:可以正确识别 NaN(尽管 NaN !== NaN)。

  3. 对象引用敏感:只匹配相同内存地址的对象。

  4. 值类型敏感:严格类型检查,不同类型但值相同的元素被区分。

  5. 对比 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

示例

  1. 基本类型检查

    js
    const colorSet = new Set(["red", "green", "blue"]);
    console.log(colorSet.has("green")); // true
    console.log(colorSet.has("yellow")); // false
  2. 特殊值检查

    js
    const specialSet = new Set([null, undefined, NaN]);
    console.log(specialSet.has(null));      // true
    console.log(specialSet.has(undefined)); // true
    console.log(specialSet.has(NaN));       // true
  3. 对象检查

    js
    const userSet = new Set();
    const alice = { name: "Alice" };
    userSet.add(alice);
    
    console.log(userSet.has(alice));                 // true
    console.log(userSet.has({ name: "Alice" }));     // false(不同对象)
  4. 动态变化检测

    js
    const 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()()修改原集合,用于一次性移除集合中的所有元素

核心特性

  1. 完全清空:移除集合中所有元素

  2. 原地操作:直接修改原集合,不创建新集合

  3. 高效执行:时间复杂度为 O(1)(直接重置内部数据结构)

  4. 引用保留:其他引用该集合的变量同步清空

    js
    const setA = new Set([1, 2, 3]);
    const setB = setA;
    
    setA.clear();
    console.log(setB.size); // 0(同步清空)

示例

  1. 基础清空操作

    js
    const numberSet = new Set([1, 2, 3]);
    console.log(numberSet.size); // 3
    
    numberSet.clear();
    console.log(numberSet.size); // 0
  2. 空集合处理

    js
    const emptySet = new Set();
    emptySet.clear(); // 无错误
    console.log(emptySet.size); // 0
  3. 链式调用限制

    js
    const 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 的值。

  • 返回:无

核心特性

  1. 顺序保证:按照元素插入顺序遍历。

  2. 值键一致性valuekey 参数相同(为兼容 Map 设计)。

  3. 只读遍历:遍历过程中修改集合会安全处理。

  4. 未调用新元素:只遍历调用 forEach 时存在的元素。

    js
    const set = new Set([1]);
    set.forEach(v => {
      console.log(v); // 1
      set.add(2);     // 不会在此次遍历中处理
    });
  5. 不可中断:无法像 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;
    }
  6. 同步执行:回调函数同步执行

    js
    console.log('Start');
    set.forEach(v => console.log(v));
    console.log('End');
    // 输出顺序:Start → 元素 → End
  7. 空集合处理:无操作

    js
    new Set().forEach(() => {}); // 无操作

示例

  1. 基本遍历

    js
    const colorSet = new Set(['red', 'green', 'blue']);
    colorSet.forEach((value, key) => {
      console.log(`${key}: ${value}`);
    });
    // 输出:
    // red: red
    // green: green
    // blue: blue
  2. 使用 thisArg

    js
    const 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 指向的对象
  3. 修改集合(安全操作):只遍历调用 forEach 时存在的元素。

    js
    const numberSet = new Set([1, 2, 3]);
    numberSet.forEach((v, _, set) => {
      if (v === 2) set.delete(1); // 安全删除
      console.log(v); // 输出 1, 2, 3(删除不影响遍历)
    });
  4. 提前终止:无法直接终止,但可跳过剩余操作

    js
    const numberSet = new Set([1, 2, 3]);
    let count = 0;
    numberSet.forEach(v => {
      if (count >= 2) return; // 无法直接终止,但可跳过剩余操作
      console.log(v);
      count++;
    });