1. 程式人生 > >es6學習筆記(七)

es6學習筆記(七)

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()
    //由於 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);
    }
    
    (2)forEach()
    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已經有值,則鍵值會被更新,否則就新生成該鍵。
    let map = new Map()
    .set(1, 'a')
    .set(2, 'b')
    .set(3, 'c');
    
    (3)get(key) get方法讀取key對應的鍵值,如果找不到key,返回undefined
    (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'];