向ES6看齊,用更好的JavaScript(三)


本文是ES6系列的第三篇,主要介紹ES6新增的數據類型、數據結構,先上傳送門:

1 第七種數據類型Symbol

ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是JavaScript語言的第七種數據類型,前六種是:Undefined、Null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。

    let s = Symbol();
    console.log(typeof s); //"symbol"

Symbol類型變量通過Symbol()方法來構建(不能使用new),另外該方法可以接受一個字符串類型的參數作為該Symbol的描述

    let s1 = Symbol('tag');
    let s2 = Symbol('tag');
    
    s1 == s2; //false,參數僅僅作為描述,就算相同描述的兩個Symbol也是不同的

Symbol類型使用注意:

    let s = Symbol();
    
    "symbol:" + s; //報錯,無法和字符串運算
    
    s + 2;  //報錯,無法和字符串運算
    
    s1.toString(); //"Symbol(tag)",Symbol顯示轉換為字符串類型是可以的
    
    if(s){
        ...         //可以轉換為bool
    }
    

說了這么多,ES6中引入Symbol到底是用來干嘛呢?

由於任意兩個Symbol都是不相等的,這就意味着我們可以將其作為對象的屬性名,而不擔心屬性名重復覆蓋原有屬性,這在團隊開發中是很有用的,舉個栗子:

    let attr = Symbol();
    
    //方法1
    let obj = {};
    obj[attr] = 'hello';  
    
    //方法2
    let obj = {
        [attr]: 'hello'
    }
    
    //方法3
    let obj = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    
    //上面三種定義屬性的方式效果是一樣的
    obj[attr]; //"hello"
    
    //方法4
    let obj = {};
    obj.attr = 'hello';
    obj[attr];  //undefined,注意不能使用“.”運算符

另外通過Symbol定義的函數是不會被for...in等遍歷出來的,如果要遍歷Symbol屬性要使用Object.getOwnPropertySymbols來遍歷Symbol屬性,或使用另一個新的APIReflect.ownKeys遍歷所有屬性(包括Symbol和其它屬性),看例子:

    
    var attr1 = Symbol('a1');
    var attr2 = Symbol('a2');
    
    var obj = {
        [attr1]:'hello',
        [attr2]:'world',
        name:'vicfeel'
    };
    
    for(let attr in obj){
        console.log(attr); //name,僅遍歷到name屬性
    }
    
    Object.getOwnPropertySymbols(obj);//[Symbol(a1),Symbol(a2)]僅遍歷Symbol屬性
    
    Reflect.ownKeys(obj);  //[Symbol(a1),Symbol(a2),name],遍歷所有屬性

2 新的數據結構Set

Set數據結構和數組類似,區別在於Set內元素是唯一不重復的,Set函數可以接受一個數組(或類似數組的對象)作為參數,用來初始化,可以通過add方法添加元素,看栗子:

   //ES6環境下
   
   //Set的方法
   //Set - 構造函數,參數為一個數組
   let arr = [1,2,3,3,4,4];
   let s = new Set(arr);//Set{1,2,3,4}
   
   //add - 添加一個值,返回結構本身
   s.add(5); //Set{1,2,3,4,5}
   s.add(2); //Set{1,2,3,4,5}
   s.add(6).add(7);//Set{1,2,3,4,5,6,7}
   
   //delete - 刪除一個值,返回一個布爾值表明刪除是否成功
   s.delete(6); //true,Set{1,2,3,4,5,7}
   
   //has - 判斷是否包含該值,返回一個布爾值
   let ok = s.has(6);//false,Set{1,2,3,4,5,7}
   
   //clear - 清空Set
   s.clear();//Set{}
   
   //Set的屬性
   s.size; //0,與數組不同set通過size獲取大小
   s.add(5);
   s.size; //1
   

Set內元素具有唯一性,因此最直觀的用途便是數組去重,現在我們可以這樣實現數組去重:

    function unique(arr){
        return [...new Set(arr)]; //...運算符參看ES6系列(二)
        
        //或者 return Array.from(new Set(arr));
    }

Set是如何界定兩元素是否相同呢,我們來測試一下:

    let s = new Set();
    s.add(5);  //Set{5}
    s.add('5');  //Set{5,'5'},不會進行類型轉換,是通過"==="而不是“==”
    
    let [n1,n2] = [NaN,NaN];
    s.add(n1);  //Set{5,'5',NaN}
    s.add(n2);  //Set{5,'5',NaN},只有一個NaN表明在Set內NaN是相等的
    
    s.add({});  //Set{5,'5',NaN,{}}
    s.add({});  //Set{5,'5',NaN,{},{}},任意兩個對象是不相等的
  • 我們來簡單看一下另一個和Set類似的數據結構WeakSet

WeakSet結構與Set類似,也是不重復的值的集合。但是,它與Set有兩個區別。

(1)WeakSet的成員只能是對象,而不能是其他類型的值。

    var ws = new WeakSet();
    ws.add(1)
    // TypeError: Invalid value used in weak set
    ws.add(Symbol())
    // TypeError: invalid value used in weak set

(2)WeakSet中的對象都是弱引用,即垃圾回收機制不考慮WeakSet對該對象的引用,也就是說,如果其他對象都不再引用該對象,那么垃圾回收機制會自動回收該對象所占用的內存,不考慮該對象還存在於WeakSet之中。這個特點意味着,無法引用WeakSet的成員,因此WeakSet是不可遍歷的。

3 新數據結構Map

map一詞本身就有映射的意思,Map數據結構提供了一種完善的鍵值對結構,之所以稱之為完善是相對於之前而言,我們知道JS中的對象Object本身就是一種鍵值對hash結構,然而這種鍵值對確是不完善的。

Object中只能將字符串作為鍵,無法使用對象作為鍵,Map數據結構的提出就是為了解決這個問題,來看個栗子:

    var a = {};
    var p = {name:'vicfeel'};
    a[p] = 'val';
    a;//Object {[object Object]: "val"},p對象被轉換成了字符串“[Object Object]”

來看一下Map數據結構的基礎用法:

    //構造函數
    var m = new Map();
    var p = {name:'vicfeel'};
    //添加鍵值對
    m.set(p,'val');
    //獲取鍵值對
    m.get(p); //"val"
    m.get('name'); //undefined
    //返回大小
    m.size; //1
    //重復添加相同鍵會覆蓋先前的
    m.set(p,'newVal');
    m.get(p); //"newVal"
    
    //利用包含鍵值對的數組初始化Map,相同鍵后面也會覆蓋前面
    var arr = [{'name':'vicfeel'},{'age':23},{'age':25}];
    var m2 = new Map(arr);
    m2.get('age'); //25
    
    //判斷是否含有某個鍵
    m2.has('name');  //true
    //刪除某個鍵
    m2.delete('name');
    m2.has('name'); //false
    
    //清空
    m2.clear();
    m2.size; //0

另外,另外Map數據結構也有一個forEach方法用於遍歷:

    let m = new Map();
    m.set('name','vicfeel').set('age',25);
    m.forEach(function(val,key,map){
        console.log("Key: %s, Value: %s", key, value);
        //Key: name, Value: vicfeel
        //Key: age, Value: 25
    });

4 Iterator(遍歷器)

雖然本篇博客寫的是新的數據類型和數據結構,遍歷器並不在此列,將Iterator放在這里是因為其與上面提到的Set、Map聯系比較緊,趁熱打鐵,便在此一起說了。

首先要說明遍歷器(Iterator)是一種機制、一種接口,它為各種不同的數據結構提供統一的訪問機制。任何數據結構只要部署Iterator接口(ES6規定,默認的Iterator接口部署在數據結構的Symbol.iterator屬性),就可以完成遍歷操作(即依次處理該數據結構的所有成員)。

ES新提供的遍歷方法for...of的遍歷方式便是自動尋找該對象的Iterator接口,一些數據結構是默認部署Iterator接口的,包括數組、Set和Map結構、偽數組(比如arguments對象、DOM NodeList對象)、后文的Generator對象,以及字符串,因此這些數據結構是可以直接使用for...of進行遍歷的,看栗子:

    let arr = [1,2,3];
    for(let item of arr){
        item;
        //1
        //2
        //3
    }
    
    let s = new Set(arr);
    for(let item of s){
        item;
        //1
        //2
        //3
    }
    
    let m = new Map();
    m.set('name','vicfeel');
    m.set('age',23);
    let p = {'width':100,'height':200};
    m.set(p,'val');
    for(let item of m){
        item;
        //["name", "vicfeel"]
        //["age", 23]
        //[{'width':100,'height':200},'val']
    }
    
    let str = 'hello';
    for(let item of str){
        item;
        //'h'
        //'e'
        //...
    }
    

對於未部署Iterator接口的結構想要對其使用for...of遍歷可自己部署Iterator接口,比如對象Object默認是不部署Iterator接口的,因為系統不知道從哪個屬性開始遍歷以及按照什么樣的次序進行遍歷,我們一個對象來看一下如何部署Iterator接口:

    let obj = {
      data: [ 'hello', 'world' ],
      [Symbol.iterator]() {
        const self = this;
        let index = 0;
        return {
          //Iterator通過next()函數進行遍歷,直至next函數返回的done值為true
          next() {
            if (index < self.data.length) {
              return {
                value: self.data[index++],
                done: false
              };
            } else {
              return { value: undefined, done: true };
            }
          }
        };
      }
    };
    
    for(let item of obj){
        item;
        //'hello'
        //'world'
    }

參考Reference http://www.ecma-international.org/ecma-262/6.0/index.html http://es6.ruanyifeng.com/ http://www.cnblogs.com/Wayou/p/es6_new_features.html http://www.cnblogs.com/sker/p/5520518.html

博文作者:vicfeel 博文出處:http://www.cnblogs.com/vicfeel 本文版權歸作者和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文鏈接,謝謝合作! 如果閱讀了本文章,覺得有幫助,您可以為我的博文點擊“推薦一下”!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM