Set与Map是都是Es6中提供的新的数据结构,大部分语言中都有的两个数据结构。
!!!做题时有效的使用Set与Map会对代码产生很好的优化。
接下来让我们了解有关Set与Map的基本特点与应用。
Set
Set类似于数组,但它的值是唯一的。(这块还有一个有意思的特点,我们稍后再说)
- 本质上Set就是一个函数(构造函数),所以我们需要使用new关键字来使用它。
- Set中可存储任意类型的数据。
- Set是可以被遍历的(这个非常重点,我也是深入学习之后才发现的)。
- 两个Set对象都不相同,即使内部存的内容全相同。
Set的属性和方法
- add(x) 方法用于向Set中添加新值,它的返回值就是一个Set结构。
- delete(x) 方法用于删除Set中的值,返回值为布尔类型,用于表示是否删除成功。
- has(x) 方法用于判断Set中是否包含某个值,返回值为布尔类型,用于判断是否包含该值。
- clear() 方法用于清空Set中所有的成员。
- size 用于得到当前Set中一共有多少元素,返回一个数字。
- keys() 方法用于遍历Set数据结构,返回Set中的所有的键名。
- values() 方法用于遍历Set数据结构,返回Set中所有的键值。
- entries() 方法用于遍历Set数据结构,返回Set中多有的键值对。
- forEach() 方法用于遍历Set中所有的元素。
<script>
const set = new Set(["aa", "bb", "cc"]);
console.log(set.keys()); //SetIterator {'aa', 'bb', 'cc'}
console.log(set.values()); //SetIterator {'aa', 'bb', 'cc'}
console.log(set.entries()); //SetIterator {'aa' => 'aa', 'bb' => 'bb', 'cc' => 'cc'}
for (let key of set.keys()) {
console.log(key);
}
// aa
// bb
// cc
for (let val of set.values()) {
console.log(val);
}
// aa
// bb
// cc
for (let item of set.entries()) {
console.log(item);
}
// (2) ['aa', 'aa']
// (2) ['bb', 'bb']
// (2) ['cc', 'cc']
for (let item of set) {
console.log(item);
}
// aa
// bb
// cc
set.forEach((key, val) => console.log(key + " " + val));
// aa aa
// bb bb
</script>
从上方这段代码,大家可以看出set 其实也可以看成是键与值时刻保持一致的特殊的Map。我也怀疑他的唯一性其实是根据它的键与值的相同实现来的 这里仅代表个人观点!!!
Map
Map 就是包含一组键值对的结构,它是一种集合类型。
- Map数据类型的get操作时间复杂度低至O(1)。
- Map产生一种映射关系,这种映射关系可以实现快速的修改和获得。
- Map可以传入一个嵌套类型的数组进行初始化映射。
Set的属性和方法
- set(x,y) 方法用于向Map中添加新值, 注意 x可以是一个对象。
- get(x) 获得x对应的value值
- has(x) 方法用于判断Map中是否包含某个值,返回值为布尔类型,用于判断是否包含该值。
- clear()方法用于清空Map中所有的成员。
- delete(x) 删除键为x的键值对。
- keys() 方法用于遍历Map数据结构,返回Map中的所有的键名。
- values() 方法用于遍历Map数据结构,返回Map中所有的键值。
- entries() 方法用于遍历Map数据结构,返回Map中多有的键值对。
- forEach() 方法用于遍历Set中所有的元素。
<script>
const map = new Map([
["aa", 1],
["bb", 2],
["cc", 3],
]);
console.log(map) // Map(3) {'aa' => 1, 'bb' => 2, 'cc' => 3}
console.log(map.keys()); //MapIterator {'aa', 'bb', 'cc'}
console.log(map.values()); //MapIterator {1, 2, 3}
console.log(map.entries()); //MapIterator {'aa' => 1, 'bb' => 2, 'cc' => 3}
for (let key of map.keys()) {
console.log(key);
}
// aa
// bb
// cc
for (let val of map.values()) {
console.log(val);
}
// 1
// 2
// 3
for (let item of map.entries()) {
console.log(item);
}
// (2) ['aa', 1]
// (2) ['bb', 2]
// (2) ['cc', 3]
for (let item of map) {
console.log(item);
}
// (2) ['aa', 1]
// (2) ['bb', 2]
// (2) ['cc', 3]
map.forEach((key, val) => console.log(key + " " + val));
// 1 aa
// 2 bb
// 3 cc
</script>
Set扩充
因为最最近看到了一个这样子的题,所以想起来为大家补充一下这部分内容,以防大家以后面试遇到这样的题会因为没在意而出错。
let set2 = new Set(['aas', 'aas'])
console.log(set2.size)//1
let set3 = new Set([NaN, NaN]) //1
console.log(set3.size)//1
let set4 = new Set([{}, {}])
console.log(set4.size)//2
let set7 = new Set([[1, 2, 3], [1, 2, 3]])
console.log(set7.size)//2
let set5 = new Set([undefined, undefined])
console.log(set5.size)//1
let set6 = new Set([null, null])
console.log(set6.size)//1
let set8 = new Set([true, true])
console.log(set8.size)//1
因为数组和对象是引用数据类型,所以像[1,2,3] [1,2,3]还有{} {}这样的虽然长得特别像,但是因为存储他们的地址是不同的,所以在Set中存储也是不一样的两个内容。故输出为2。(这块就引出了,js基本数据类型与引用数据类型存储的方式是不同的)