es6确实对es进行了较大的改动,从数据类型的变化就能反映出很大一部分。这一篇主要讲一下Symbol、Proxy和Reflect、Set、Map这四方面。
symbol
es5的对象属性名都是字符串,在实际使用的过程中, 如果不注意命名的话,有可能会产生完全相等的命名,这样就会产生属性名冲突,尤其在复用他人代码时更是尤为常见,,为此es6引入了一种新的原始数据类型Symbol,表示独一无二的值,简单的一句就可定义完毕。
let s = Symbol('youarepig')
//控制台打印是 Symbol(youarepig)
typeof s //"symbol"
基本上可以说,Symbol是一种类似字符串的数据结构,不过还有下面几条需要注意:
1.不能对其使用new命令
2.它可以接受一个字符串作为参数,描述Symbol实例,相当于一个称呼,区分一下不同的实例,但要注意,就算传入的字符串是一样的,两个Symbol实例也是不相等的
3.Symbol值不能和其他类型值进行运算,否则会报错
4.Symbol可以显式转化为字符串,也可以转化为布尔值,但不能转化为数值
5.区分不同参数的Symbol可以console打印
6.作为对象属性名时,不能使用点运算符,而要使用[]
Symbol.for() Symbol.keyFor()
Symbol.for()传入一个字符串参数key,用来寻找以该参数key为名称的Symbol值,在全局变量中检索后如果找到了Symbol,则直接返回它,如果找到则调用Symbol()函数新创建一个Symbol值返回,这在我们需要重复使用一个Symbol时会非常有用。另外笔者在当前最新版(55)的chorme浏览器上尝试了一下,如果创建过两个相同key的Symbol后,在对此key使用Symbol.for()后会返回一个Symbol,并且与前两个Symbol都不完全相等(===)。
Symbol.keyFor()返回一个已登记的Symbol类型值的key。
另外Symbol还有一些内置的方法,这里就不做介绍了。
Proxy和Reflect
Proxy用于修改某些操作的默认行为,等同于在语言层面上作出修改,所以属于一种“元编程”,即对编程语言进行编程。
Proxy可以理解为在对象架设了一“拦截”层,外界的访问都必须经过这个“拦截”层,所以这就提供了一种机制,对外界的访问和操作进行过滤和改写。
var obj = new Proxy({}, {
get:function( target, key, receiver ){
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set:function(target, key, value, receiver){
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.count=1
//setting count!
++obj.count
//getting count!
//setting count!
//2
以上的代码表明,Proxy实际上重载了点运算符,即用自己的定义覆盖了源语言的定义。es6提供了Proxy构造函数,用于生成Proxy实例,其手中new Proxy()表示生成一个Proxy实例,需传入第一个参数是target表示锁妖拉捏的目标对象,第二个参数handle是一个对象,用来定制拦截行为。
Reflect对象设计目的有以下几个:
1.将Object对象的一些明显属于语言层面的方法放到Reflect对象上。
2.修改某些Object方法的返回结果,让其变得更合理。
3.让Object操作都变成函数行为。
3.Reflect对象的方法与Proxy对象的方法一一对应。
Set和Map
es6提供的Set数据结构类似数组,但其中的成员都是唯一的,没有重复值,可以理解为trim处理后的数组。
let a = [1,2,3,4,4]
s = new Set(a)
s.size //4
s.add(1) //Set{1, 2, 3, 4}
Set使用new Set构造函数进行构造,可以向其直接传递数组作为参数进行初始化,也可以通过Set.add方法加入成员,如果值已经存在则无法重复加入,长度属性为size,new Set().size返回Set内成员个数。
Set的操作方法有四个,add delete has clear
遍历方法有四个,keys values entries forEach 以及额外的扩展运算符(...)。
有了set后,我们进行数组去重,以及求数组并集、交集、差集等方便了许多
[...new Set([1,2,3,4,4])] //[1,2,3,4]去重
new Set([...[1,2],...[2,3]]) //Set{1,2,3}并集
new Set([1,2,3].filter(x => new Set([1,2]).has(x))) //Set {1, 2} 交集
new Set([1,2,3].filter(x => !new Set([1,2]).has(x))) //Set {3} 差集
另外简单介绍一下set类似结构WeakSet,其与Set主要有两个区别,WeakSet成员只能是对象,不能是其他类型;对象都是弱引用,即垃圾回收制不考虑WeakSet对该对象的引用,这意味着无法引用WeakSet成员,因此WeakSet是不可遍历的。其一个用处就是储存DOM节点,不用担心这些节点从文档移除时会引发内存泄漏。
Map结构类似于对象,也是键值对的集合,但是键的范围不仅仅是字符串,而是各种类型的值甚至包括对象,所以Map是一种比对象更加灵活的hash结构,其实际上提供了一种‘值-值’对应的结构。
let m = new Map()
m.set(['a'], 1)
m.get(['a']) //undefined
当键是引用类型时,只有引用地址是一样的才能算为一个键,这极大程度解决了同名属性碰撞问题。
另外介绍一下常用的属性和方法
size表示成员数目, set get delete claer has keys values entries forEach以及扩展运算符(...)(转化为数组)
另外其还有一个延伸结构,WeakMap与Map的区别是他只接受对象作为键名,而且键名所值对象不计入垃圾回收机制。其一个应用就是储存DOM节点作为键名。
以上三部分内容,其实都是对对象进行了一系列的扩展,形成了一个更加便捷完善的运用体系,同时总体尅明显看出es6使得js往函数式编程语言的方向前进,大量使用链式调用结构,靠拢数学处理。