JavaScript中Set对象研究01_Set基本介绍_实例方法:add、clear、delete、difference、has、entries、keys、values、forEach、union

JavaScript中Set对象研究01:Set基本介绍、实例方法add、clear、delete、has、entries、keys、values、forEach、集合运算(union、difference)

在现代JavaScript开发中,Set对象作为一种集合数据结构,提供了存储唯一值的方式,无论这些值是什么类型。
本文将深入研究Set对象,包括其基本介绍、Set()构造函数,以及一系列常用的实例方法,如addcleardeletehasentrieskeysvaluesforEach。此外,我们还将探讨如何实现集合的**并集(union)差集(difference)**操作。


一、Set基本介绍

1. 什么是Set对象?

Set对象是ES6(ECMAScript 2015)引入的一种新的集合数据结构,用于存储唯一值的有序列表。Set中没有键值对,只有值(value),且每个值在集合中只能出现一次,这意味着Set内部不会有重复的值。

特点:
  • 值的唯一性Set集合中的值都是唯一的,没有重复。
  • 值的类型多样性Set可以存储任何类型的值,包括基本类型和对象引用。
  • 迭代特性Set对象是可迭代的,支持for...of循环等迭代方式。

2. 为什么使用Set?

在处理需要唯一性的数据集合时,Set提供了比数组更方便和高效的方式。例如,从一个包含重复元素的数组中获取唯一值列表,或者在添加元素时自动去重。

优势:
  • 自动去重:无需手动检查重复,Set会自动确保元素的唯一性。
  • 高效的查找Set提供了has方法,可以快速判断某个值是否存在于集合中。
  • 丰富的方法Set提供了多种方法,方便对集合进行操作和遍历。

二、Set()构造函数

1. 创建Set对象

Set对象可以通过Set()构造函数创建。可以创建一个空的Set,也可以使用可迭代对象(如数组)初始化Set

语法:
// 创建空的Set
const set = new Set();

// 使用可迭代对象初始化Set
const set = new Set(iterable);
  • iterable:一个可迭代的对象,其所有元素将被添加到新的Set中。

2. 示例

(1)创建空的Set
const mySet = new Set();
(2)使用数组初始化Set
const mySet = new Set([1, 2, 3, 4, 5]);

console.log(mySet.size); // 5
(3)自动去重功能
const mySet = new Set([1, 2, 2, 3, 4, 4, 5]);

console.log(mySet.size); // 5
console.log([...mySet]); // [1, 2, 3, 4, 5]
(4)使用字符串作为值
const mySet = new Set(['apple', 'banana', 'orange', 'apple']);

console.log(mySet.size); // 3
console.log([...mySet]); // ['apple', 'banana', 'orange']

3. 注意事项

  • 如果iterable中存在重复的值,Set会自动过滤,只保留一个。
  • 值的比较采用“同值零等性”(SameValueZero),类似于严格相等===,但NaN被认为等于NaN

三、Set实例方法

Set对象提供了一系列实例方法,用于操作集合。以下是常用的实例方法:

  • add(value)
  • clear()
  • delete(value)
  • has(value)
  • entries()
  • keys()
  • values()
  • forEach(callback[, thisArg])

1. add(value)

定义

add()方法向Set对象添加一个指定的值,如果该值已存在,则不会发生任何变化。

语法
set.add(value);
  • value:要添加到Set对象中的值。
返回值
  • 返回Set对象本身,可以链式调用。
示例
const mySet = new Set();

mySet.add(1);
mySet.add(5).add(5).add(10); // 链式调用,重复的值5不会被添加多次

console.log(mySet.size); // 3
console.log([...mySet]); // [1, 5, 10]
注意事项
  • 如果添加的值已存在于Set中,集合不会发生变化。

2. clear()

定义

clear()方法移除Set对象中的所有元素。

语法
set.clear();
示例
const mySet = new Set([1, 2, 3]);

console.log(mySet.size); // 3

mySet.clear();

console.log(mySet.size); // 0
注意事项
  • clear()方法不返回值,执行后Set对象将变为空。

3. delete(value)

定义

delete()方法从Set对象中移除指定的元素。

语法
set.delete(value);
  • value:要移除的值。
返回值
  • true:如果成功移除对应的值。
  • false:如果值不存在于Set中。
示例
const mySet = new Set([1, 2, 3]);

console.log(mySet.size); // 3

mySet.delete(2); // 返回 true

console.log(mySet.size); // 2
console.log(mySet.has(2)); // false

mySet.delete(5); // 返回 false,因为值不存在
注意事项
  • 如果值不存在,delete()方法返回falseSet对象不发生变化。

4. has(value)

定义

has()方法返回一个布尔值,表示Set对象中是否存在指定的值。

语法
set.has(value);
  • value:要检查的值。
示例
const mySet = new Set([1, 2, 3]);

console.log(mySet.has(2)); // true
console.log(mySet.has(5)); // false
console.log(mySet.has(NaN)); // false

mySet.add(NaN);
console.log(mySet.has(NaN)); // true

5. entries()

定义

entries()方法返回一个新的Iterator对象,包含Set对象中所有元素的键值对,键和值相同。

语法
set.entries();
示例
const mySet = new Set(['apple', 'banana', 'orange']);

for (const [key, value] of mySet.entries()) {
  console.log(`${key} => ${value}`);
}

// 输出:
/*
apple => apple
banana => banana
orange => orange
*/
注意事项
  • 由于Set没有键的概念,所以entries()方法返回的键和值是相同的。

6. keys()

定义

keys()方法返回一个新的Iterator对象,包含Set对象中的所有元素。

语法
set.keys();
示例
const mySet = new Set([1, 2, 3]);

for (const key of mySet.keys()) {
  console.log(key);
}

// 输出:
/*
1
2
3
*/
注意事项
  • 对于Set对象,keys()方法与values()方法功能相同,都是返回集合中的元素。

7. values()

定义

values()方法返回一个新的Iterator对象,包含Set对象中的所有元素。

语法
set.values();
示例
const mySet = new Set(['a', 'b', 'c']);

for (const value of mySet.values()) {
  console.log(value);
}

// 输出:
/*
a
b
c
*/

8. forEach(callback[, thisArg])

定义

forEach()方法对Set对象中的每个值,按照插入顺序调用一次callback函数。

语法
set.forEach(callback[, thisArg]);
  • callback(value, key, set):为每个元素执行的函数。
    • value:当前元素的值。
    • key:对于Set对象,keyvalue相同。
    • set:调用forEach()Set对象本身。
  • thisArg:可选,执行callback函数时,用作this的值。
示例
const mySet = new Set([1, 2, 3]);

mySet.forEach((value, key, set) => {
  console.log(`Value: ${value}, Key: ${key}`);
});

// 输出:
/*
Value: 1, Key: 1
Value: 2, Key: 2
Value: 3, Key: 3
*/
使用thisArg
const mySet = new Set([1, 2, 3]);

const multiplier = {
  factor: 2,
  multiply(value) {
    return value * this.factor;
  }
};

mySet.forEach(function(value) {
  console.log(`${value} * ${this.factor} = ${this.multiply(value)}`);
}, multiplier);

// 输出:
/*
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
*/
注意事项
  • forEach()方法的回调函数的参数与MapforEach()一致,但keyvalue相同。
  • 如果需要中途停止迭代,可以考虑使用for...of循环,配合breakreturn

四、Set的遍历

除了上述的entries()keys()values()forEach()方法,Set对象还可以通过迭代器和解构赋值进行遍历。

1. 使用for...of循环

const mySet = new Set(['x', 'y', 'z']);

for (const value of mySet) {
  console.log(value);
}

// 输出:
/*
x
y
z
*/

2. 使用扩展运算符

const mySet = new Set([1, 2, 3]);

const setArray = [...mySet];
console.log(setArray); // [1, 2, 3]

3. 使用Array.from()

const mySet = new Set(['a', 'b', 'c']);

const arrayFromSet = Array.from(mySet);
console.log(arrayFromSet); // ['a', 'b', 'c']

五、集合运算

在2024年已经支持了如并集(union)和差集(difference)、判断子集等功能,但我们可以通过自定义函数来实现这些功能。

1. 并集(union)

并集是指两个集合的所有元素的集合。

实现并集
function union(setA, setB) {
  const resultSet = new Set(setA);
  for (const value of setB) {
    resultSet.add(value);
  }
  return resultSet;
}

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

const unionSet = union(setA, setB);
console.log([...unionSet]); // [1, 2, 3, 4, 5]

2. 差集(difference)

差集是指属于第一个集合但不属于第二个集合的元素的集合。

实现差集
function difference(setA, setB) {
  const resultSet = new Set(setA);
  for (const value of setB) {
    resultSet.delete(value);
  }
  return resultSet;
}

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

const differenceSet = difference(setA, setB);
console.log([...differenceSet]); // [1]

3. 交集(intersection)

交集是指同时属于两个集合的元素的集合。

实现交集
function intersection(setA, setB) {
  const resultSet = new Set();
  for (const value of setA) {
    if (setB.has(value)) {
      resultSet.add(value);
    }
  }
  return resultSet;
}

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

const intersectionSet = intersection(setA, setB);
console.log([...intersectionSet]); // [2, 3]

4. 子集(subset)

判断一个集合是否是另一个集合的子集。

实现子集判断
function isSubset(setA, setB) {
  for (const value of setA) {
    if (!setB.has(value)) {
      return false;
    }
  }
  return true;
}

// 示例
const setA = new Set([1, 2]);
const setB = new Set([1, 2, 3]);

console.log(isSubset(setA, setB)); // true
console.log(isSubset(setB, setA)); // false

六、应用示例

1. 数组去重

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

const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

2. 字符串中独特字符的统计

function countUniqueChars(str) {
  return new Set(str).size;
}

console.log(countUniqueChars('hello')); // 4 ('h', 'e', 'l', 'o')
console.log(countUniqueChars('world')); // 5

3. 过滤重复对象

const items = [
  { id: 1, name: 'apple' },
  { id: 2, name: 'banana' },
  { id: 1, name: 'apple' },
];

const uniqueItems = Array.from(new Set(items.map(item => JSON.stringify(item)))).map(item => JSON.parse(item));

console.log(uniqueItems);
/*
[
  { id: 1, name: 'apple' },
  { id: 2, name: 'banana' }
]
*/

七、注意事项

  • 值的相等性Set使用“同值零等性”比较值,这意味着0-0被认为是相同的值,而NaN可以作为有效的值,并且NaN === NaNSet中为true

    const mySet = new Set();
    mySet.add(NaN);
    console.log(mySet.has(NaN)); // true
    
  • 不可重复性Set中不会有重复的值,如果尝试添加重复的值,Set会忽略它。

  • 遍历顺序Set会按照元素添加的顺序进行遍历,因此可以预测遍历的顺序。

  • Set与数组的转换:可以使用扩展运算符或Array.from()Set和数组之间进行转换。

    const mySet = new Set([1, 2, 3]);
    const myArray = [...mySet]; // [1, 2, 3]
    
  • Set的性能:对于频繁的增删查操作,Set的性能通常优于数组,因为Sethas方法在平均情况下的时间复杂度为O(1)。


参考资料


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

It'sMyGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值