產生起因
JavaScript的默認對象表示方式{}
可以視爲其他語言中的Map
或Dictionary
的數據結構,即一組鍵值對。
但是JavaScript的對象有個小問題,就是鍵必須是字符串。但實際上Number或者其他數據類型作爲鍵也是非常合理的。爲了解決這個問題,最新的ES6規範引入了新的數據類型Map
和set
.
Set是一種叫做集合的數據結構,Map是一種叫做字典的數據結構
應用場景
數組去重和數據存儲
Set (集合)[類數組]
-
集合是由一組無序且唯一(即不能重複)的項組成的,可以想象成集合是一個既沒有重複元素,也沒有順序概念的數組
var a = new Set([1, 2, 3, {"1": "2"}, ["3","4"]])
-
ES6提供了新的數據結構Set。它類似於數組,但是成員的值都是唯一的,沒有重複的值
-
Set 本身是一個構造函數,用來生成 Set 數據結構
這裏說的Set其實就是我們所要講到的集合,先來看下基礎用法
const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for (let i of s) { console.log(i); // 2 3 5 4 } // 去除數組的重複成員 let array = [1,2,1,4,5,3]; [...new Set(array)] // [1, 2, 4, 5, 3]
方法和屬性總結
-
屬性
-
add(value):添加某個值,返回 Set 結構本身。
-
delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
-
has(value):返回一個布爾值,表示該值是否爲 Set 的成員。
-
clear():清除所有成員,無返回值。
-
size: 返回set數據結構的數據長度
let set = new Set(); console.log(set.add(1).add(2)); // Set [ 1, 2 ] console.log(set.delete(2)); // true console.log(set.has(2)); // false console.log(set.clear()); // undefined console.log(set.has(1)); // false console.log(set.size); // 0
-
-
遍歷方法有
-
keys():返回鍵名的遍歷器
-
values():返回鍵值的遍歷器
-
entries():返回鍵值對的遍歷器
-
forEach():使用回調函數遍歷每個成員,無返回值
let set = new Set(['a', 'b', 'c']); console.log(set.keys()); // SetIterator {"a", "b", "c"} console.log([...set.keys()]); // ["a", "b", "c"]
let set = new Set(['a', 'b', 'c']); console.log(set.values()); // SetIterator {"a", "b", "c"} console.log([...set.values()]); // ["a", "b", "c"]
let set = new Set(['a', 'b', 'c']); console.log(set.entries()); // SetIterator {"a", "b", "c"} console.log([...set.entries()]); // [["a", "a"], ["b", "b"], ["c", "c"]]
let set = new Set([1, 2, 3]); set.forEach((value, key) => console.log(key + ': ' + value)); // 1: 1 // 2: 2 // 3: 3
-
方法剖析(實現原理)
-
建一個集合
function Set(arr = []) { // 可以傳入數組 let items = {}; this.size = 0; // 記錄集合中成員的數量 } module.exports = Set;
這裏用{}對象來表示集合,也是因爲對象不允許一個鍵指向兩個不同的屬性,保證了集合裏的元素都是唯一的
-
has方法
// has(val)方法 this.has = function (val) { // 對象都有hasOwnProperty方法,判斷是否擁有特定屬性 return items.hasOwnProperty(val); };
-
add方法
// add(val)方法 this.add = function (val) { if (!this.has(val)) { items[val] = val; this.size++; // 累加集合成員數量 return true; } return false; };
-
keys、values方法
// keys()方法 this.keys = function () { return Object.keys(items); // 返回遍歷集合的所有鍵名的數組 }; // values()方法 this.values = function () { return Object.values(items); // 返回遍歷集合的所有鍵值的數組 };
-
forEach方法
// forEach(fn, context)方法 this.forEach = function(fn, context = this) { for (let i = 0; i < this.size; i++) { let item = Object.keys(items)[i]; fn.call(context, element, sameElement, set); } };
-
Array.from()
將Set類數組轉化爲真實的數組
let arrayLike = { 0: 'tom', 1: '65', 2: '男', 3: ['jane','john','Mary'], 'length': 4 } let arr = Array.from(arrayLike) console.log(arr) // ['tom','65','男',['jane','john','Mary']]
-
與Array之間的關係
-
var myArray = ["value1", "value2", "value3"]; // 用Set構造器將Array轉換爲Set var mySet = new Set(myArray); mySet.has("value1"); // returns true // 用...(展開操作符)操作符將Set轉換爲Array console.log([...mySet]); // 與myArray完全一致
-
高級用法
let set = new Set([2, 1, 3]); console.log(set.keys()); // [ '1', '2', '3' ] console.log(set.values()); // [ 1, 2, 3 ] console.log(set.size); // 3 set.delete(1); console.log(set.values()); // [ 2, 3 ] set.clear(); console.log(set.size); // 0 // 並集 let a = [1, 2, 3]; let b = new Set([4, 3, 2]); let union = new Set(a).union(b).values(); console.log(union); // [ 1, 2, 3, 4 ] //或者 let a = new Set([1, 2, 3, 4]) let b = new Set([4, 5, 6]) let union = new Set([...a, ...b]) console.log(union) //1 2 3 4 5 6 去掉重複的4 // 交集 let c = new Set([4, 3, 2]); let intersect = new Set([1,2,3]).intersect(c).values(); console.log(intersect); // [ 2, 3 ] //或者 let a = new Set([1, 2, 3, 4]) let b = new([4, 5, 6]) let difference = [...a].filter(function(ele) { return b.has(ele); }) // 4 //箭頭函數 let difference = [...a].filter(x => x.has(x)) // 4 // 差集 let d = new Set([4, 3, 2]); let difference = new Set([1,2,3]).difference(d).values(); // [1,2,3]和[4,3,2]的差集是1 console.log(difference); // [ 1 ] //或者 let a = new Set([1, 2, 3, 4]) let b = new([4, 5, 6]) let difference = [...a].filter(function (ele) { return !b.has(ele); }) // 1, 2, 3
Map (字典)[類對象]
它類似於對象,也是鍵值對的集合,但是“鍵”的範圍不限於字符串,各種類型的值(包括對象)都可以當作鍵,是一種更完善的 Hash 結構實現。如果你需要“鍵值對”的數據結構,Map 比 Object 更合適;
那麼集合又和字典有什麼區別呢:
-
共同點:集合、字典可以存儲不重複的值
-
不同點:集合是以[值,值]的形式存儲元素,字典是以[鍵,值]的形式存儲
這裏說的Set其實就是我們所要講到的集合,先來看下基礎用法
const m = new Map(); const o = {p: 'Hello World'}; m.set(o, 'content') m.get(o) // "content" m.has(o) // true m.delete(o) // true m.has(o) // false
方法和屬性總結
-
屬性
size:返回字典所包含的元素個數
-
操作方法
-
set(key, val): 向字典中添加新元素
-
get(key):通過鍵值查找特定的數值並返回
-
has(key):如果鍵存在字典中返回true,否則false
-
delete(key): 通過鍵值從字典中移除對應的數據
-
clear():將這個字典中的所有元素刪除
-
let m = new Map(); m.set('Jay', 'Jay的Chou'); m.set(true, '真的'); console.log(m.has('Chou')); // false console.log(m.size); // 2 console.log(m.keys()); // [ 'Jay', 'true' ] console.log(m.values()); // [ 'Jay的Chou', '真的' ] console.log(m.get('jay')); // undefined m.delete(true); console.log(m.keys()); // [ 'Jay' ] console.log(m.values()); // [ 'Jay的Chou' ]
由於一個key只能對應一個value,所以,多次對一個key放入value,後面的值會把前面的值沖掉:
var m = new Map(); m.set('Adam', 67); m.set('Adam', 88); m.get('Adam'); // 88
Map方法接受一個二維數組當做參數
var m = new Map([['name', 'zhangsan'],['sex', 'male']]); console.log(m); //Map {"name" => "zhangsan", "sex" => "male"}
-
-
遍歷方法有
-
keys():將字典中包含的所有鍵名以數組形式返回
-
values():將字典中包含的所有數值以數組形式返回
-
entries():返回鍵值對的遍歷器
-
forEach():遍歷字典的所有成員
var map = new Map([['age', 19],['height', 180]]); for (let key of map.keys()) { console.log(key); // age height } for (let value of map.values()) { console.log(value); //19 180 } for (let item of map.entries()) { console.log(`${ item[0] }: ${ item[1] }`); //age: 19 height: 180 } for (let [key, value] of map.entries()) { console.log(`${ key }: ${ value }`); //age: 19 height: 180 } for (let [key, value] of map) { console.log(`${ key }: ${ value }`); //age: 19 height: 180 } map.forEach((value, key, map) => { console.log(`${ key }: ${ value }`); //age: 19 height: 180 });
-
方法剖析(實現原理)
-
建一個字典
function Map() { let items = {}; } module.exports = Map; // 導出
-
has方法
// has(key)方法 this.has = function (val) { return items.hasOwnProperty(val); };
-
set和get方法
// set(key, val)方法 // set相同key時,後面聲明的會覆蓋前面 // 如: new Map().set({}, 'a') this.set = function (key, val) { items[key] = val; }; // get(key)方法 this.get = function (key) { // 判斷是否有key,如果有的話直接返回對應的值 // 如果讀取一個未知的鍵,則返回undefined return this.has(key) ? items[key] : undefined; };
-
keys、values方法
// keys()方法 this.keys = function () { return Object.keys(items); // 返回遍歷集合的所有鍵名的數組 }; // values()方法 this.values = function () { return Object.values(items); // 返回遍歷集合的所有鍵值的數組 };
-
forEach方法
// forEach(fn, context)方法 this.forEach = function(fn, context = this) { for (let i = 0; i < this.size; i++) { let item = Object.keys(items)[i]; fn.call(context, element, sameElement, set); } };
-
與Array之間的關係
//Map轉數組 const map = new Map(); map.set('name' , 'hello').set({},'world'); [...map] //[["name","hello"],[{},"world"]] [...map.value()] //[["hello","world"] //數組轉Map const map = new Map([["name","hello"],[{},"world"]]); map // {"name" => "hello", Object {} => "world"}
-
與對象之間的關係
//Map轉爲對象的方法 function strMapToObj(strMap) { let obj = Object.create(null); for (let [k,v] of strMap) { obj[k] = v; } return obj; } let myMap = new Map().set('name', 'Virgo').set('old', '18'); console.log(strMapToObj(myMap));// { name: "Virgo", old: "18"} //對象轉爲Map的方法 function objToStrMap(obj) { let strMap = new Map(); for (let k of Object.keys(obj)) { strMap.set(k, obj[k]); } return strMap; } var a = {name: 'Virgo', old: '18'} console.log(objToStrMap(a))//Map(2){"name" => "Virgo", "old" => "18"}