本文是ES6系列的第三篇,主要介紹ES6新增的數據類型、數據結構,先上傳送門:html
ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是JavaScript語言的第七種數據類型,前六種是:Undefined、Null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。es6
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],遍歷全部屬性
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是如何界定兩元素是否相同呢,咱們來測試一下:this
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,{},{}},任意兩個對象是不相等的
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是不可遍歷的。
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 });
雖然本篇博客寫的是新的數據類型和數據結構,遍歷器並不在此列,將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 本文版權歸做者和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文連接,謝謝合做! 若是閱讀了本文章,以爲有幫助,您能夠爲個人博文點擊「推薦一下」!