本文是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 本文版权归做者和博客园共有,欢迎转载,但须保留此段声明,并给出原文连接,谢谢合做! 若是阅读了本文章,以为有帮助,您能够为个人博文点击“推荐一下”!