一、Map
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值)都可以作为键或值。
描述
Map 对象是键值对的集合。Map 中的一个键只能出现一次;它在 Map 的集合中是独一无二的。
Map 对象按键值对迭代——一个 for…of 循环在每次迭代后会返回一个形式为 [key, value] 的数组。迭代按插入顺序进行,即键值对按 set() 方法首次插入到集合中的顺序(也就是说,当调用 set() 时,map 中没有具有相同值的键)进行迭代。
键是如何对比相等
键的比较基于零值相等算法。(它曾经使用同值相等,将 0 和 -0 视为不同。)这意味着 NaN 是与 NaN 相等的(虽然 NaN !== NaN),剩下所有其他的值是根据 === 运算符的结果判断是否相等。
基本使用
实例属性:size(Map长度)
实例方法:
- Map.prototype.get():返回与指定的键 key 关联的值,若不存在关联的值,则返回 undefined。
- Map.prototype.has():返回一个布尔值,用来表明 Map 对象中是否存在与指定的键 key 关联的值。
- Map.prototype.keys():返回一个新的迭代器对象,其包含 Map 对象中所有元素的键,以插入顺序排列。
- Map.prototype.set():在 Map 对象中设置与指定的键 key 关联的值,并返回 Map 对象。
- Map.prototype.values():返回一个新的迭代对象,其中包含 Map 对象中所有的值,并以插入 Map 对象的顺序排列。
- Map.prototype.clear():移除 Map 对象中所有的键值对。
- Map.prototype.delete():移除 Map 对象中指定的键值对,如果键值对存在并成功被移除,返回 true,否则返回 false。调用 delete 后再调用 map.has(key) 将返回 false。
- Map.prototype.entries():返回一个新的迭代器对象,其包含 Map 对象中所有键值对 [key, value] 二元数组,以插入顺序排列。
- Map.prototype.forEach():以插入顺序为 Map 对象中的每个键值对调用一次 callbackFn。如果为 forEach 提供了 thisArg 参数,则它将作为每一次 callback 的 this 值。
- Map.prototype [Symbol.iterator] () 返回一个新的迭代器对象,其包含 Map 对象中所有元素 [key, value] 二元数组,以插入顺序排列。
const myMap =newMap();const keyString ="a string";const keyObj ={};constkeyFunc=function(){};// 添加键
myMap.set(keyString,"和键'a string'关联的值");
myMap.set(keyObj,"和键 keyObj 关联的值");
myMap.set(keyFunc,"和键 keyFunc 关联的值");
console.log(myMap.size);// 3// 读取值
console.log(myMap.get(keyString));// "和键'a string'关联的值"
console.log(myMap.get(keyObj));// "和键 keyObj 关联的值"
console.log(myMap.get(keyFunc));// "和键 keyFunc 关联的值"
console.log(myMap.get("a string"));// "和键'a string'关联的值",因为 keyString === 'a string'
console.log(myMap.get({}));// undefined,因为 keyObj !== {}
console.log(myMap.get(function(){}));// undefined,因为 keyFunc !== function () {}
可迭代
const myMap =newMap();
myMap.set(0,"zero");
myMap.set(1,"one");for(const[key, value]of myMap){
console.log(`${key} = ${value}`);}// 0 = zero// 1 = onefor(const key of myMap.keys()){
console.log(key);}// 0// 1for(const value of myMap.values()){
console.log(value);}// zero// onefor(const[key, value]of myMap.entries()){
console.log(`${key} = ${value}`);}// 0 = zero// 1 = one
Map与数组
const kvArray =[["key1","value1"],["key2","value2"],];// 使用常规的 Map 构造函数可以将一个二维的键值对数组转换成一个 Map 对象const myMap =newMap(kvArray);
console.log(myMap.get("key1"));// "value1"// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维的键值对数组
console.log(Array.from(myMap));// 输出和 kvArray 相同的数组// 更简洁的方法来做如上同样的事情,使用展开运算符
console.log([...myMap]);// 或者在键或者值的迭代器上使用 Array.from,进而得到只含有键或者值的数组
console.log(Array.from(myMap.keys()));// 输出 ["key1", "key2"]
复制Map
const original =newMap([[1,"one"]]);const clone =newMap(original);
console.log(clone.get(1));// one
console.log(original === clone);// false. 浅比较 不为同一个对象的引用
合并Map
Map 对象间可以进行合并,但是会保持键的唯一性。后面的会覆盖前面的。
const first =newMap([[1,"one"],[2,"two"],[3,"three"],]);const second =newMap([[1,"uno"],[2,"dos"],]);// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的。// 展开语法本质上是将 Map 对象转换成数组。const merged =newMap([...first,...second]);
console.log(merged.get(1));// uno
console.log(merged.get(2));// dos
console.log(merged.get(3));// three
Map与数组合并
const first =newMap([[1,"one"],[2,"two"],[3,"three"],]);const second =newMap([[1,"uno"],[2,"dos"],]);// Map 对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。const merged =newMap([...first,...second,[1,"eins"]]);
console.log(merged.get(1));// eins
console.log(merged.get(2));// dos
console.log(merged.get(3));// three
与Object对比
MapObject键默认不包含任何键,只包含显示存入的键值对。键可以为任何值(包括函数、对象以及任何原始类型)Object有原型,所以包含默认的键。键类型必须为String或Symbol大小size属性获取Object.keys().length迭代可迭代没有迭代协议,不能通过for…of迭代性能在涉及频繁添加和删除键值对的场景中表现更好未针对频繁添加和删除键值对进行优化
二、Set
Set 对象存储任何类型(无论是原始值还是对象引用)的唯一值。
描述
Set 对象是值的合集(collection)。集合(set)中的元素只会出现一次,即集合中的元素是唯一的。你可以按照插入顺序迭代集合中的元素。插入顺序对应于 add() 方法成功将每一个元素插入到集合中(即,调用 add() 方法时集合中不存在相同的元素)的顺序。
如何对比值的相等
值的相等是基于零值相等算法的。(曾使用会将 0 和 -0 视为不同值的同值算法。参见浏览器兼容性。)这意味着 NaN 和 undefined 会被视为是相同的值(即使 NaN !== NaN),而所有其他的值则基于 === 运算符的语义进行相等比较。
性能
has 方法检查某个值是否在集合中,其采用的方式的平均时间比逐个测试先前添加到集合中的元素更快。特别是当一个数组的长度(length)等于集合的大小(size)时,这比 Array.prototype.includes 方法的平均速度更快。
基本使用
实例属性:size(Map长度)
实例方法:
- Set.prototype.add(): 在 Set 对象中插入一个新的具有指定值的元素。
- Set.prototype.clear(): 从 Set 对象中移除所有元素。
- Set.prototype.delete():移除与 value 关联的元素,并返回一个布尔值来表示是否移除成功。Set.prototype.has(value) 会在此之后返回 false。
- Set.prototype.entries():返回一个新的迭代器对象,该对象包含 Set 对象中的代表每个元素的 [value, value] 数组。这与 Map 对象类似,因此 Set 的每个条目的 key 和 value 都相同。
- Set.prototype.forEach():按照值插入的顺序为 Set 对象中的每个值调用一次 callbackFn。如果提供了 thisArg 参数,它将被用作每次调用 callbackFn 时的 this 值。
- Set.prototype.has():返回一个布尔值,表示给定值在 Set 对象中是否存在。
- Set.prototype.keys():Set.prototype.values() 的别名。
- Set.prototype.values():返回一个新的迭代器对象,该对象按插入顺序生成 Set 对象中每个元素的值。
- Set.prototype [Symbol.iterator] ():返回一个新的迭代器对象,该对象按插入顺序生成 Set 对象中每个元素的值。
const mySet1 =newSet();
mySet1.add(1);// Set(1) { 1 }
mySet1.add(5);// Set(2) { 1, 5 }
mySet1.add(5);// Set(2) { 1, 5 }
mySet1.add("some text");// Set(3) { 1, 5, 'some text' }const o ={a:1,b:2};
mySet1.add(o);
mySet1.add({a:1,b:2});// o 是不同对象的引用,所以这是可以的
mySet1.has(1);// true
mySet1.has(3);// false,因为并未将 3 添加到集合中
mySet1.has(5);// true
mySet1.has(Math.sqrt(25));// true
mySet1.has("Some Text".toLowerCase());// true
mySet1.has(o);// true
mySet1.size;// 5
mySet1.delete(5);// 从集合中移除 5
mySet1.has(5);// false,5 已从集合中移除
mySet1.size;// 4,因为我们刚刚移除了一个值
mySet1.add(5);// Set(5) { 1, 'some text', {...}, {...}, 5 }——先前删除的元素会作为新的元素被添加,不会保留删除前的原始位置
console.log(mySet1);// Set(5) { 1, "some text", {…}, {…}, 5 }
与数组的关系
const myArray =["value1","value2","value3"];// 使用常规的 Set 构造函数将 Array 转换为 Setconst mySet =newSet(myArray);
mySet.has("value1");// 返回 true// 使用展开语法将 Set 转换为 Array。
console.log([...mySet]);// 将显示与 myArray 完全相同的数组
数组去重
// 用于从数组中删除重复元素const numbers =[2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5];
console.log([...newSet(numbers)]);// [2, 3, 4, 5, 6, 7, 32]
零值相等算法
原本js中,NaN !== NaN,但是零值相等算法视为相等,-0 与 0也视作相等。
const set =newSet([NaN,NaN]);
console.log(set);// Set(1) {NaN}const set1 =newSet([0,-0]);
console.log(set1);// Set(1) {0}
与Array对比
SetArray值允许存储重复的值不允许存储重复的值。如果尝试向 Set 添加一个已经存在的值,该值将被忽略。元素的类型判断使用严格相等(===)判断元素是否相等使用零值相等算法,类似于严格相等(===),但 NaN 被视为等于 NaN,-0 === 0。性能在添加、删除和查找元素时具有更高的性能,特别是对于大量数据。处理大量数据不如Set
使用场景
Array:适用于需要存储有序且可能包含重复元素的数据的场景,如列表、队列、栈等。
Set:适用于需要存储唯一值的集合,如在需要检查是否包含某个值或需要快速去重时。
版权归原作者 田本初 所有, 如有侵权,请联系我们删除。