ES6 新增了两个数据结构,一个是 set,另一个是 map。前端
在《你不知道的 JavaScript(下卷)》中是这么定义的:set 是一个值的集合,其中的值惟一(重复会被忽略)。 它相似于数组,可是每一个成员的值是惟一的。 set 是一个构造函数,能够经过 new 来建立一个 set 实例。git
let set = new Set([1, 2, 3, 1, 4]);
console.log(set); // {1, 2, 3, 4} 复制代码
上述能够看出,new Set 会自动过滤掉重复值,并返回一个集合,咱们能够利用这个特性,来写出简单的数组去重。es6
let set = new Set([1, 2, 3, 1, 4]);
let arr = [...set]; console.log(arr); // [1, 2, 3, 4] 复制代码
set 经过 add()来增长成员,将新值放在集合尾部,若是新值跟原集合中的成员重复的话,会被自动过滤掉。github
let set = new Set([1, 2, 3, 1, 4]);
set.add(1); console.log(set); // {1, 2, 3, 4} let set = new Set([1, 2, 3, 1, 4]); set.add(0); console.log(set); // {1, 2, 3, 4, 0} 复制代码
Set 的构造函数能够接受一个具备 Iterable 接口的其余数据结构做为参数。编程
// 例1
let set = new Set("string"); console.log(set); // {"s", "t", "r", "i", "n", "g"} // 例2 function foo(a, b) { let set = new Set(arguments); console.log(set); // {1, 2} } foo(1, 2); 复制代码
set 的实例属性有两个:数组
实例方法分为两类,一个是操做类,一个是遍历类。 操做类:markdown
// 例1
let set = new Set([1, 2, 3]); set.clear(); console.log(set); // {} // 例2 let set = new Set([1, 2, 3]); let result = set.delete(1); console.log(result); // true console.log(set); // {2, 3} // 例3 let set = new Set([1, 2, 3]); let result = set.has(1); console.log(result); // true 复制代码
遍历类:数据结构
// 例1
let set = new Set([1, 2, 3]); let keys = set.keys(); console.log(keys); // {1, 2, 3} // 例2 let set = new Set([1, 2, 3]); let values = set.values(); console.log(values); // {1, 2, 3} 复制代码
上述两个例子,由于 Sset 没有键名,只有值,因此 keys 和 values 的结果是同样的。 Set 一样拥有 forEach 方法:函数
let set = new Set([1, 2, 3]);
set.forEach((key, value) => { console.log(`${key}:${value}`); }); // 1:1 // 2:2 // 3:3 复制代码
跟数组的 forEach 方法不一样的是,它的回调函数的参数是其 key 值和 value 值,可是 Set 没有 key 值,因此其 key 和 value 相等。forEach 的第二个参数是 this 值,其绑定的是回调函数中的 this 值。 最后一个实例方法是 entries:oop
let set = new Set([1, 2, 3]);
let entries = set.entries(); console.log(entries); // { // [1, 1], // [2, 2], // [3, 3] // } 复制代码
enteries()返回一个遍历器,返回一个键值对,但其键值对均相等。
WeakSet 也是一个构造函数,与 Set 一直,WeakSet 和 Set 二者类似但不一样,不一样点主要有两个:
let weakSet = new WeakSet([1, 2]); // Uncaught TypeError: Invalid value used in weak set
let weakSet = new WeakSet([ [1, 2], [3, 4], ]); // {[1, 2], [3, 4]} 复制代码
WeakSet 有三个实例方法:
var ws = new WeakSet();
var foo = {}; var bar = {}; ws.add(foo); ws.add(bar); ws.has(foo); // true ws.has(bar); // true ws.delete(foo); // 从set中删除 foo 对象 ws.has(foo); // false, foo 对象已经被删除了 ws.has(bar); // true, bar 依然存在 复制代码
在 JS 中对象是建立无序键 / 值对数据结构 [ 也称为 映射(map)] 的主要机制。可是,对象做为映射的主要缺点是不能使用非字符串值做为键。因此在 ES6 提出一个新的数据结构,Map。 Map 和对象很相似,都是键值对的形式,可是 Map 的键能够是任意类型(对象或者原始值),NaN 也能够做为键,再也不只局限于字符串。 任何具备 Iterator 接口、且每一个成员都是一个双元素的数组的数据结构均可以看成 Map 构造函数的参数。
let map = new Map([[{a:1},3]]);
console.log(map);//{ { a:1 },3} 复制代码
在 MDN 中清晰的列出了 Map 和 Object 间的不一样:
Map | Object | |
---|---|---|
意外的键 | Map 默认状况不包含任何键。只包含显式插入的键。 | 一个 Object 有一个原型, 原型链上的键名有可能和你本身在对象上的设置的键名产生冲突。注意: 虽然 ES5 开始能够用 Object.create(null) 来建立一个没有原型的对象,可是这种用法不太常见。 |
键的类型 | 一个 Map 的键能够是任意值,包括函数、对象或任意基本类型。 | 一个 Object 的键必须是一个 String 或是 Symbol。 |
键的顺序 | Map 中的 key 是有序的。所以,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 | 一个 Object 的键是无序的。注意:自 ECMAScript 2015 规范以来,对象确实保留了字符串和 Symbol 键的建立顺序; 所以,在只有字符串键的对象上进行迭代将按插入顺序产生键。 |
Size | Map 的键值对个数能够轻易地经过 size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,因此能够直接被迭代。 | 迭代一个 Object 须要以某种方式获取它的键而后才能迭代。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未做出优化。 |
Map 的实例属性有两个:
实例方法分为两类,一个是操做类,一个是遍历类。 操做类:
let map = new Map();
let key = {name:"Jack"}; let value = "啥"; map.set(key, value); //{ { name:'Jack' }:'啥'} map.get(key); // '啥' map.get(a); // undefined map.has(key); // true map.delete(key); // true map.clear(); // {} 复制代码
遍历类:
let map = new Map([
["name","Jack"], [{age:25},"啥"], ]); map.entries(); // MapIterator {"name"=>"Jack",{age:25}=>"啥"} for (let item of map.entries()) { console.log(item); // ["name","Jack"] [{age:25},"啥"] } map.forEach((value, key, map) => { console.log(value, key, map); // Jack name Map(2) {"name"=>"Jack",{age: 25}=>"啥"} //"啥"{age:25} Map(2) {"name" =>"Jack",{age:25}=>"啥"} }); map.keys(); // MapIterator {"name",{age:25}} for (let item of map.keys()) { console.log(item); // "name" {age:25} } map.values(); // MapIterator {"Jack","啥"} for (let item of map.values()) { console.log(item); // "Jack" "啥" } 复制代码
ES6 给出一个最简单的方式,扩展运算符。
let map = new Map([
["name", "Jack"], [{ age: 25 }, "啥"], ]); console.log([...map]); // [['name', 'Jack'], [{age: 25}, '啥']] 复制代码
除此以外还能够用 Array.from()。
let map = new Map([
["name", "Jack"], [{ age: 25 }, "啥"], ]); console.log(Array.from(map)); // [['name', 'Jack'], [{age: 25}, '啥']] 复制代码
若是全部 Map 的键都是字符串,它能够无损地转为对象。
function strMapToObj(strMap) {
let obj = Object.create(null); for (let [k, v] of strMap) { obj[k] = v; } return obj; } const myMap = new Map().set("yes", true).set("no", false); strMapToObj(myMap); // { yes: true, no: false } 复制代码
Map 转 JSON 有两个形式,第一种是键名都是字符串的类型的,第二种是键名中包含非字符串类型。 第一种的话直接将 map 转为对象,而后再用 JSON.Stringfy()进行转换。 第二种的话能够转成数组 JSON。
function mapToArrayJson(map) {
return JSON.stringify([...map]); } let myMap = new Map().set(true, 7).set({ foo: 3 }, ["abc"]); mapToArrayJson(myMap); // '[[true,7],[{"foo":3},["abc"]]]' 复制代码
WeakMap 和 WeakSet 有些相似,都是弱引用,而且成员值的键必须是对象。
let weakMap = new WeakMap([[1,3]]); // Uncaught TypeError: Invalid value used as weak map key
let weakMap = new WeakMap([[{name:"Jack"},3]]); // {{name:'Jack'}:3} 复制代码
WeakMap 有四个实例方法:
let weakMap = new WeakMap();
let obj = {name: 'Jack'}; weakMap.set(obj, 3); // {{name:'Jack'}: 3} weakMap.get(obj); // 3 weakMap.has(obj); // true weakMap.delete(obj); // true 复制代码
Map 的应用最直接的就是策略模式。举个例子若是一个公司的年终奖为一等奖是电脑,二等奖是手机,三等奖是步步高点读机,四等奖是矿泉水。那通常会这么写:
function getAnnualBonus(level) {
if (level === "一等奖") { return "电脑"; } else if (level === "二等奖") { return "手机"; } else if (level === "三等奖") { return "步步高点读机"; } else if (level === "四等奖") { return "矿泉水"; } } getAnnualBonus("一等奖"); // 或者 function getAnnualBonus(level) { switch (level) { case "一等奖": return "电脑"; case "二等奖": return "手机"; case "三等奖": return "步步高点读机"; case "四等奖": return "矿泉水"; default: break; } } getAnnualBonus("一等奖"); 复制代码
上述两种写法,若是条件愈来愈多的话,那写的 if...else...和 case 愈来愈长,代码至关的臃肿。 运用 Map 来写策略模式,简洁明了:
let annualBonus = new Map([
['一等奖', '电脑'], ['二等奖', '手机'], ['三等奖', '步步高点读机'], ['四等奖', '矿泉水'] ]); function getAnnualBonus(level) { return annualBonus.get(level); } getAnnualBonus("一等奖"); 复制代码
相关文章:
以为还能够的,麻烦走的时候能给点个赞,让更多人能看到这篇文章,你们一块儿学习和探讨!不点赞的都是耍流氓😂
还能够关注个人博客但愿能给个人github上点个Start,小伙伴们必定会发现一个问题,个人全部用户名几乎都与番茄有关,由于我真的很喜欢吃番茄❤️!!!
想跟车不迷路的小伙还但愿能够关注公众号 前端老番茄 或者扫一扫下面的二维码👇👇👇。
我是一个编程界的小学生,您的鼓励是我不断前进的动力,😄但愿能一块儿加油前进。
本文使用 mdnice 排版