引言
【ES6】聊聊ES6中JS新增的两种"原始数据类型"及"类型判断"的四种方法(2)
在上篇文章中我们聊到了ES6
新增的两种原始数据类型及其特性,今天我们来聊聊ES6
新增的两种引用数据类型Set
和Map
以及set
和WeakSet
之间的区别。Set
和Map
的出现为 JavaScript
中的数据存储和处理提供了更多灵活和高效的选择,特别是在需要存储唯一值
或者键值对
的情况下。引入这两种数据结构丰富了 JavaScript
的语言特性,使得开发者能够更方便地处理各种数据结构的需求。下面我会为大家详细介绍Set
和Map
这两种数据结构以及为大家分析Set
和Weakset
的区别。
迭代器(Iterator)
在讲这两种数据结构之前我们需要引入一个迭代器(Iterator)
概念
概念
在JavaScript中,迭代器
(Iterator)是一种对象,它提供了一种统一的方式来遍历
数据结构中的元素
,比如数组
、Set
、Map
等。
实际上,许多内置数据结构
都实现了迭代器接口,使得它们可以使用相同的方式进行遍历操作。你可以使用for...of
循环或者调用迭代器对象的next
方法来遍历这些数据结构,这里我们用for...of循环来判断该数据类型是否具有迭代器接口属性。
for...of循环遍历
在JavaScript中,for...of
循环提供了一种便捷的方式来遍历可迭代对象
(iterable),比如数组
、Set
、Map
等。它相对于传统的for
循环和forEach
方法来说,语法更加简洁,同时可以处理各种不同类型的数据结构。如果一个数据结构拥有迭代器
这个接口
,也就是说明这个数据结构是能被for...of遍历
的。
示例
js
let arr = [1, 2, 3, 4];
for (let element of arr) {
console.log(element);// 1 2 3 4
}
在这个示例中,for...of
循环会迭代
数组arr
中的每一个元素,并将当前元素赋值给变量element
,然后执行循环体内的代码。因为数组是拥有迭代器
这个接口的,所以我们可以用for...of
来对其循环遍历。
除了数组,我们也可以使用for...of
循环来遍历其他可迭代对象,比如Set
和Map
:
js
let mySet = new Set([1, 2, 3, 4]);
for (let value of mySet) {
console.log(value);
}
let myMap = new Map([['a', 1], ['b', 2]]);
for (let [key, value] of myMap) {
console.log(key, value);
}
需要注意的是,for...of
循环只能用于可迭代对象
,如果你想要遍历普通的对象(object)
,你可以使用for...in
循环来实现。此外,for...of
循环在遍历时会自动调用对象的迭代器
(如果对象有的话),因此它非常适合用于处理可迭代对象的情况。
总的来说,for...of
循环为JavaScript
中的可迭代对象
提供了一种简洁而统一的遍历方式
,使得我们可以更加方便地处理各种类型的数据结构
。
Set
JavaScript中的Set是一种数据结构,用于存储不重复的值。它类似于数组,但与数组不同的是,Set中的元素不能重复出现。这意味着在Set中添加相同的值只会保留一个,我们称Set创建的对象为类数组。
js
let arr = [1,1,2,3,3]
console.log(arr)
let set = new Set([1,1,2,3,3])
console.log(set)
我们在浏览器中打印这段代码,从执行的结果我们可以看出数组
和set
的区别和相似之处,他们都是以数组
形式输出结果,但是Set
输出的结果中并没有重复项
,而且Set
可以被遍历输出就说明它也拥有迭代器
这个接口属性。
我们在浏览器中声明一个Set类型的变量,并打印该对象,可以看到这个对象拥有的属性和其隐式原型内的方法,首先其拥有size属性,则说明我们可以往其中手动添加值,并且在下面我们会对这些常用方法进行举例说明。
Set中的 key 和 values 方法
在JavaScript中,
Set
对象提供了一些方法来获取其成员的键(keys)
和值(values)
。然而,需要指出的是,由于Set
是一种集合类型,它没有键值对
的概念,因此在Set
中键
和值是
相同的,这是我们可以将键值对中的:和键值省略只写一个键值。不过,Set对象仍提供了keys()和values()方法,这两个方法的作用是相同的,都是用来返回Set对象中的值。
下面我来为大家分别介绍一下keys()和values()方法:
- keys()方法:
Set
对象的keys()
方法返回一个新的迭代器对象
,包含了Set
对象中的所有值,顺序与插入顺序一致。
js
let mySet = new Set(['a', 'b', 'c']);
let keysIter = mySet.keys();
for (let key of keysIter) {
console.log(key);
}
// 输出:
// a
// b
// c
- values()方法:
values()
方法与keys()
方法类似,也返回一个新的迭代器对象
,包含了Set
对象中的所有值。
js
let mySet = new Set(['a', 'b', 'c']);
let valuesIter = mySet.values();
for (let value of valuesIter) {
console.log(value);
}
// 输出:
// a
// b
// c
需要注意的是,由于Set
对象中的键和值是相同的,因此无论是使用keys()
方法还是values()
方法,它们都会返回Set对象中的值。这与Map
对象的keys()
和values()
方法有所不同,因为Map
对象中的键和值是分开存储的。
总的来说,使用keys()
和values()
方法可以方便地遍历Set
对象中的值,尤其适用于需要对集合中的值进行处理的情况。
Set中的 add 和 delete 方法
在 JavaScript 中,
Set
对象提供了add()
和delete()
方法,用于向Set
中添加
新元素和删除
现有元素。
- add() 方法:
add()
方法用于向Set
中添加新元素。如果添加的值在Set
中已经存在,则Set
不会发生改变。
js
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(3);
console.log(mySet); // 输出: Set { 1, 2, 3 }
- delete() 方法:
delete()
方法用于从Set
中删除指定的元素。如果Set
中存在该元素,则它将被移除并返回true
;如果不存在,则返回false
。
js
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(3);
console.log(mySet); // 输出: Set { 1, 2, 3 }
mySet.delete(2);
console.log(mySet); // 输出: Set { 1, 3 }
需要注意的是,add()
方法返回的是 Set
对象本身,因此可以进行链式调用
。而 delete()
方法则返回一个布尔值
,指示是否成功删除了指定的元素。
这些方法使得在 Set
对象中添加
和删除
元素变得非常便捷,可以方便地维护集合的内容。
Set中的 clear 和 has 方法
在 JavaScript 中,
Set
对象还提供了clear()
和has()
方法,用于清空Set
中的所有元素以及检查指定元素是否存在。
- clear() 方法:
clear()
方法用于清空Set
中的所有元素,使得Set
变为空集。
javascript
let mySet = new Set([1, 2, 3]);
console.log(mySet); // 输出: Set { 1, 2, 3 }
mySet.clear();
console.log(mySet); // 输出: Set {}
- has() 方法:
has()
方法用于检查Set
中是否包含指定的元素。如果Set
中包含该元素,则返回true
;否则返回false
。
javascript
let mySet = new Set([1, 2, 3]);
console.log(mySet.has(2)); // 输出: true
console.log(mySet.has(4)); // 输出: false
这两个方法可以方便地管理 Set
对象中的元素。clear()
方法可以在需要时快速清空集合,而 has()
方法则可以帮助我们检查指定元素是否存在于集合中。
Set中的size方法
在 JavaScript 中,
Set
对象中的size
属性用于获取Set
实例中元素的数量,即Set
的大小。
下面是一个简单的示例:
javascript
let mySet = new Set([1, 2, 3, 4, 5]);
console.log(mySet.size); // 输出: 5
在上面的示例中,mySet
是一个包含 1 到 5 的 Set 对象,并且通过访问 size
属性可以知道该对象包含了多少个元素。
size
属性提供了一种方便的方式来获取 Set
对象的大小,而无需像数组那样使用 length
属性。
Map
在 JavaScript 中,
Map
是一种新的数据结构,用于存储键值对
。它提供了一种更灵活的方式来存储和操作数据,相比于普通的对象
,Map
对象具有以下特点:
- 键的类型不限于字符串,可以是任意数据类型,甚至是对象、函数等。
- Map 对象中的元素是有序的,可以通过迭代器遍历,而对象的属性则没有固定的顺序。
- Map 对象的 size 属性可以获取键值对的数量,方便进行统计和管理。
下面是 Map 对象常用的方法:
- set(key, value) 方法:向 Map 中添加或更新指定键的值。
javascript
let myMap = new Map();
myMap.set('name', 'Alice');
myMap.set(1, 'One');
console.log(myMap)//Map(2) {size: 2, name => Alice, 1 => One}
- get(key) 方法:获取指定键的值。
javascript
console.log(myMap.get('name')); // 输出: Alice
console.log(myMap.get(1)); // 输出: One
- has(key) 方法:检查 Map 中是否包含指定的键。
javascript
console.log(myMap.has('name')); // 输出: true
console.log(myMap.has('age')); // 输出: false
- delete(key) 方法:从 Map 中删除指定键及其对应的值。
javascript
myMap.delete('name');
console.log(myMap.has('name')); // 输出: false
- clear() 方法:清空 Map 中的所有键值对。
javascript
myMap.clear();
console.log(myMap.size); // 输出: 0
这些方法使得在 Map
对象中添加
、获取
、删除
元素变得非常便捷,同时也提供了对键值对
进行有效管理的能力。
弱引用集合:WeakSet
JavaScript
是一门灵活且动态的编程语言,其生态系统中不断涌现出新的特性
和数据结构
。其中之一就是 ECMAScript 6(ES6)
引入的 WeakSet
,它为开发者提供了一种存储对象引用的集合方式,具有弱引用
的特性。
弱引用的概念
在理解 WeakSet
之前,我们首先需要了解什么是弱引用
。在 JavaScript 中,当我们创建一个对象
并将其赋值给一个变量时,这个变量会持有该对象的引用
。只要有变量持有着对对象的引用
,对象就不会被垃圾回收
。
而弱引用
与之不同,它不会阻止对象被垃圾回收
。如果一个对象只被弱引用
持有,而在程序的其他地方没有其他引用
指向它,这个对象就会被垃圾回收
。这为解决内存泄漏
问题提供了一种机制。
弱引用集合:WeakSet 的特性
WeakSet
就是利用了弱引用
的概念,它是一种集合
,专门用于存储对象引用
。下面是一些关于 WeakSet
的重要特性:
1. 弱引用存储
WeakSet
中存储的对象是弱引用的,不会阻止这些对象被垃圾回收
。这意味着当程序中没有其他地方引用这个对象时,它会被自动从 WeakSet
中移除。
2. 只能存储对象
WeakSet
只能存储对象引用
,而不能存储原始值
。这是因为原始值
没有被垃圾回收
的概念,弱引用
对于原始值
没有意义。
3. 不可迭代
由于弱引用
的特性,WeakSet
是不可迭代的。因此,不能使用 forEach
等迭代方法直接访问其中的元素。
4. 没有 size
属性和 clear
方法
由于 WeakSet
不可迭代,因此没有类似 size
属性和 clear
方法的属性和方法。我们无法直接获取 WeakSet
中元素的数量。
5. 没有键名和值之分
WeakSet
只关心对象引用的存在与否,不关心键名和值的区别。只要对象引用存在,就被视为存在于 WeakSet
中。
使用示例
下面是一个简单的示例,演示了如何使用 WeakSet
:
js
// 创建一个 WeakSet
let weakSet = new WeakSet();
// 创建一些对象
let obj1 = { name: 'Object 1' };
let obj2 = { name: 'Object 2' };
let obj3 = { name: 'Object 3' };
// 将对象添加到 WeakSet 中
weakSet.add(obj1);
weakSet.add(obj2);
// 检查对象是否存在于 WeakSet 中
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj3)); // false
// 从 WeakSet 中删除对象
weakSet.delete(obj1);
// 检查对象是否存在于 WeakSet 中(删除后应为 false)
console.log(weakSet.has(obj1)); // false
在实际应用中,WeakSet
主要用于需要存储对象集合且不想阻止这些对象被垃圾回收的场景。它为开发者提供了一种灵活而高效的方式来处理对象引用,从而更好地管理内存和避免潜在的内存泄漏
问题。
简单聊下垃圾回收机制
我们知道JavaScript预编译
时会在调用栈
中创建全局执行上下文
和函数执行上下文
,而对象
的存储是在堆
中,如果这个执行上下文
执行完毕了,垃圾回收机制
一旦生效那么这个执行上下文
就会被移出调用栈
或者堆
,用WeakSet
声明的对象就是弱引用
类型,垃圾回收机制
一旦生效,这个对象里面的属性
就都没了,也就是被垃圾回收机制
清除了,但是当我们去浏览器中立即检查该对象中的属性时还能看见,这个问题曾一度被推上讨论榜首,后来解释而知JavaScript中垃圾回收机制并不是每时每刻生效,我们并不知道机制何时生效,但是我们可以理解为当垃圾回收机制开始生效时,若引用类型的对象就会被垃圾回收机制回收。
总结
md
# set
1. 是一种key和value相等的特殊对象
2. set 对象中的值是唯一的
3. 具有迭代器(iterator)属性
# map
1. 键的类型不限于字符串,可以是任意数据类型,甚至是对象、函数等。
1. Map 对象中的元素是有序的,可以通过迭代器遍历,而对象的属性则没有固定的顺序。
1. Map 对象的 size 属性可以获取键值对的数量,方便进行统计和管理。
# WeakSet && WeakMap
一个对象被 weakset 所引用,在垃圾回收机制的眼中该对象是没有被引用的,只要垃圾回收机制一生效,该对
象所占据的内存空间就会被销毁。
如果这篇文章感觉对你有用的话,给作者一点鼓励点个赞吧♥
作者在持续更新更多有用的干货中,关注➕收藏 Coding不迷茫
所有文章的源码,给作者的开源git仓库点个收藏吧: gitee.com/cheng-bingw...