es6學習筆記(七)
阿新 • • 發佈:2018-12-12
Symbol原始資料型別
1. 概述
- ES6 引入的一種新的原始資料型別Symbol,表示獨一無二的值。
let s = Symbol(); typeof s; //'symbol'
- Symbol函式可以接受一個字串作為引數,表示對 Symbol 例項的描述,主要是為了在控制檯顯示,或者轉為字串時,比較容易區分。
let s1 = Symbol('foo'); let s2 = Symbol('bar'); s1 //Symbol(foo) s2 //Symbol(bar)
- Symbol函式的引數只是表示對當前 Symbol 值的描述,因此相同引數的Symbol函式的返回值是不相等的。
// 沒有引數的情況 let s1 = Symbol(); let s2 = Symbol(); s1 === s2 // false // 有引數的情況 let s1 = Symbol('foo'); let s2 = Symbol('foo'); s1 === s2 // false
- Symbol 值不能與其他型別的值進行運算,會報錯。
- 但是,Symbol 值可以顯式轉為字串。
- 另外,Symbol 值也可以轉為布林值,但是不能轉為數值
2.作為屬性名的 Symbol
- 由於每個Symbol值都不相等,所以其可以作為識別符號,用於物件的屬性名,就能保證不會出現同名的屬性。可以防止某一個鍵被不小心改寫或覆蓋。
- 注意,Symbol 值作為物件屬性名時,不能用點運算子。
let mySymbol = Symbol(); // 第一種寫法 let a = {}; a[mySymbol] = 'Hello!'; // 第二種寫法 let a = { [mySymbol]: 'Hello!' }; // 第三種寫法 let a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上寫法都得到同樣結果 a[mySymbol] // "Hello!" const mySymbol = Symbol(); const a = {}; a.mySymbol = 'Hello!'; a[mySymbol] // undefined a['mySymbol'] // "Hello!" //在物件的內部,使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中 let s = Symbol(); let obj = { [s]: function (arg) { ... } }; obj[s](123);
3.屬性名的遍歷
- Symbol 作為屬性名,該屬性不會出現在for…in、for…of迴圈中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有屬性,有一個Object.getOwnPropertySymbols方法,可以獲取指定物件的所有 Symbol 屬性名。
//Object.getOwnPropertySymbols方法返回一個數組,成員是當前物件的所有用作屬性名的 Symbol 值 const obj = {}; let a = Symbol('a'); let b = Symbol('b'); obj[a] = 'Hello'; obj[b] = 'World'; const objectSymbols = Object.getOwnPropertySymbols(obj); objectSymbols // [Symbol(a), Symbol(b)]
- Reflect.ownKeys方法可以返回所有型別的鍵名,包括常規鍵名和 Symbol 鍵名
let obj = { [Symbol('my_key')]: 1, enum: 2, nonEnum: 3 }; Reflect.ownKeys(obj) // ["enum", "nonEnum", Symbol(my_key)]
4.Symbol.for(),Symbol.keyFor()
- Symbol.for 重新使用同一個 Symbol 值。它接受一個字串作為引數,然後搜尋有沒有以該引數作為名稱的 Symbol 值。如果有,就返回這個 Symbol 值,否則就新建並返回一個以該字串為名稱的 Symbol 值。
let s1 = Symbol.for('foo'); let s2 = Symbol.for('foo'); s1 === s2 // true
- Symbol.keyFor方法返回一個已登記的 Symbol 型別值的key
let s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" //變數s2屬於未登記的 Symbol 值,所以返回undefined let s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined
Set和Map資料結構
1. Set
- Set類似於陣列,但是成員的值都是唯一的,沒有重複的值
const s = new Set(); //通過add方法向Set結構加入成員,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
- Set函式接受一個數組作為引數,用來初始化,可以對陣列進行去重
const set = new Set([1,2,3,4,4]); [..set]; //[1,2,3,4] const items = new Set([1,2,3,4,5,5,5,5]); items.size //5
- 在 Set 內部,兩個NaN是相等
let set = new Set(); let a = NaN; let b = NaN; set.add(a); set.add(b); set //Set {NaN}
- 在 Set 內部,兩個物件總是不相等的
- Set 例項的屬性和方法
//add(value):新增某個值,返回 Set 結構本身 s.add(1).add(2).add(2); //返回Set例項的成員總數 s.size //2 //has(value):返回一個布林值,表示該值是否為Set的成員 s.has(1) // true s.has(2) // true s.has(3) // false //delete(value):刪除某個值,返回一個布林值,表示刪除是否成功 s.delete(2); //clear():清除所有成員,沒有返回值
- Array.from方法可以將 Set 結構轉為陣列
const items = new Set([1, 2, 3, 4, 5]); const array = Array.from(items);
- 遍歷操作
(1)keys(),values(),entries()
(2)forEach()//由於 Set 結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),所以keys方法和values方法的行為完全一致 let set = new Set(['red', 'green', 'blue']); //keys():返回鍵名的遍歷器 for (let item of set.keys()) { console.log(item); } // red // green // blue //values():返回鍵值的遍歷器 for (let item of set.values()){ console.log(item); } // red // green // blue //entries():返回鍵值對的遍歷器 for (let item of set.entries()) { console.log(item); } // ["red", "red"] // ["green", "green"] // ["blue", "blue"] //可以省略values方法,直接用for...of迴圈遍歷Set for (let x of set) { console.log(x); }
let set = new Set([1, 4, 9]); set.forEach((value, key) => console.log(key + ' : ' + value)) // 1 : 1 // 4 : 4 // 9 : 9
2.WeakSet
WeakSet 結構與 Set 類似,也是不重複的值的集合。但是,它與 Set 有兩個區別。首先,WeakSet 的成員只能是物件,而不能是其他型別的值。
3.Map
Map類似obj物件鍵值對的集合,obj的key值只能是字串,但是map“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵。
- 含義和基本用法
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
- 例項的屬性和操作方法
(1)size屬性返回 Map 結構的成員總數
(2)set(key, value),set方法設定鍵名key對應的鍵值為value,然後返回整個 Map 結構。如果key已經有值,則鍵值會被更新,否則就新生成該鍵。
(3)get(key) get方法讀取key對應的鍵值,如果找不到key,返回undefinedlet map = new Map() .set(1, 'a') .set(2, 'b') .set(3, 'c');
(4)has(key) has方法返回一個布林值,表示某個鍵是否在當前 Map 物件之中。
(5)delete(key) delete方法刪除某個鍵,返回true。如果刪除失敗,返回false。
(6)clear() clear方法清除所有成員,沒有返回值 - 遍歷方法
(1)keys():返回鍵名的遍歷器。
(2)values():返回鍵值的遍歷器。
(3)entries():返回所有成員的遍歷器。
(4)forEach():遍歷 Map 的所有成員。
4.WeakMap
WeakMap只接受物件作為鍵名(null除外),不接受其他型別的值作為鍵名。
WeakMap的鍵名所指向的物件,不計入垃圾回收機制。
5.與陣列的對比
- Map與Array的對比
//資料結構橫向對比:增、刪、改、查 let map = new Map(); let array = []; //增 map.set('t',1); array.push({t:1}); //查 let map_exist = map.has('t'); let array_exist = array.find(item =>item.t); //改 map.set('t',2); array.forEach(item => item.t?item.t=2:' ') //刪 map.delete('t'); let index = array.findIndex(item => item.t); array.splice(index,1);
- Set與Array的對比
let set = new Set(); let array = []; //增 set.add({t:1}); let array = []; //查 let set_exist = set.has({t:1}); let array_exist = array.find(item =>item.t); //改 set.forEach(item => item.t? item.t=2:''); let array_exist = array.find(item => item.t?item.t=2:' '); //刪 set.forEach(item => item.t?set.delete(item):' '); let index = array.findIndex(item => item.t); array.splice(index,1);
6.與Object的對比
- 與Object的對比
let item = {t:1}; let map = new Map(); let set = new Set(); let obj = {}; //增 map.set('t',1}; set.add(item); obj['t'] = 1; //查 map.has('t'); set.has(item); 't' in obj //改 map.set('t',2); item.t=2; obj['t']=2; //刪 map.delete('t'); set.delete(item); delete obj ['t'];