首页/ES6/列表

ES6新特性之集合(Collections)Set、Map、WeakSet和WeakMap详解

来源:  2018-04-12 10:23:01    评论:0点击:

 
 
ES5的时候我们经常用数组或者类数组对象来操作数据,而对于一些使用惯了java之类语言的集合的开发人员来说,总有少了点什么的感觉,SE6提供Set和Map这两个集合。不仅从根本上为一些问题提供了解决方案(如数据不重复),还大大提升了性能。
 
要想理解Set和Map,就要从它的根本问题说起,在进行详细的API概览之前,我觉得有必要先说明两点:
 
    遍历Set和Map的顺序就是元素插入的顺序。这是与其它语言最不一样的地方,之所以这样定是因为负责实现ES6集合模块的作者经过实验验证,在javaScript中确定顺序遍历比不确定遍历效率要高。
    Set和Map没有hash码。在其他语言,都能够自行实现一个哈希函数并暴露出系统默认的哈希函数,但在javaScript委员会选择了不暴露 。
 
关于第二点可能有些难理解,我们通过一个例子来说明:
 
    var a = {name:"Jhon"};  
    var b = {name:"Jhon"};  
    var set = new Set();  
    set.add(a).add(b);  
    console.log(set.size); //2  
    //这两个对象应该按相同处理,毕竟它们有完全一样的属性。但在JavaScript中,它们是各自独立、互不相同的。  
 
读万卷书不如操作一下,下面我就会对操作集合的这些API进行逐一的尝试验证,并且你会发现官方说明可能和浏览器实现是有差异的。
 
Set集合,没有重复元素的集合
 
 
    var a = {name:"Jhon"};  
    var b = {name:"Jhon"};  
    var set = new Set(); // 创建一个新的,空的Set  
    set.add(a).add(6); //添加两个元素,add返回集合自身,可以链式调用  
    console.log(set[0]); //undefined,不支持索引遍历  
    console.log(set.size); //打印元素个数 2  
    set.forEach(function(value){  //遍历Set  
        console.log(value); //Object { name: "Jhon" },6  
    });  
    if(set.has(a)){ //判断是否存在某个元素  
        console.log("a"); //a  
    }  
    if(set.has(b)){ //false  
        console.log("b");   
    }  
    if(set.has({name:"Jhon"})){ //false  
        console.log("other");  
    }  
    var c = [1,2,2,3,4];  
    var setc = new Set(c); //new Set(iterable) :从任何可遍历数据中提取元素,构造出一个新的集合。  
    console.log(setc.size); //4,元素去重  
    console.log(setc.delete(4));//true,官方说delete会返回集合自身,但是在最新版火狐中如果元素存在,则返回true,反之返回false,链式调用会报出错  
    console.log(setc.size); //3  
    setc.clear(); //清空Set  
    console.log(setc.size); //0<strong>  
    </strong>  
    //set.keys() 、 set.values() 和 set.entries() 返回各种迭代器,它们是为了兼容 Map 而提供的,所以我们待会儿再来看。  
 
 
Map集合,由若干键-值对组成 
    var map = new Map(); //创建一个新的,空的Map  
    map.set("one",1); //增加列表项  
    map.set("two",2);  
    console.log(map.size); //2,获取元素个数  
    if(map.has("one")){ //true,判断元素存在  
        console.log("one");  
    }  
    console.log(map.get("one")); //1,根据key获取元素  
    map.forEach(function(value, key, map){ //遍历map  
        console.log(key + ":" + value); //one:1,two:2  
    });  
    for(var key of map.keys()){ //返回key的迭代器  
        console.log(key); //one,two  
    }  
    for(var value of map.values()){ //返回值的迭代器  
        console.log(value); //1,2  
    }  
    for(var [key,value] of map.entries()){ //返回项的迭代器  
        console.log(value); //1,2  
    }  
    console.log(map.delete("one")); //true,根据key删除项  
    map.clear(); //清空map  
    console.log(map.size); //0  
      
    var a = [["one",1],["two",2]];  
    var map1 = new Map(a); //new Map(pairs),通过数组或者已存在的map创建Map  
    map1.forEach(function(value, key, map){   
        console.log(key + ":" + value); //one:1,two:2  
    });  
 
 
弱引用集合WeakSet和WeakMap
 
Map和Set都为内部的每个键或值保持了强引用,也就是说,如果一个对象被移除了,回收机制无法取回它占用的内存 ,除非在Map或者Set中删除它。
 
WeakSet并不对其中对象保持强引用。当WeakSet中的一个对象被回收时,它会简单地被从WeakSet中移除。WeakMap也类似地不为它的键保持强引用。如果一个键仍被使用,相应的值也就仍被使用 。
下面是弱引用集合的一些限制:
 
    WeakMap只支持new、has、get、set 和delete。 
    WeakSet只支持new、has、add和delete 。
    WeakSet的值和WeakMap的键必须是对象。
    都不可迭代,除非专门查询或给出你感兴趣的键,否则不能获得一个弱集合中的项 。
 
以上就是ES6集合的操作以及注意事项。
 
 
 
 
ES6终于加入了高级的数据结构集合,包括Map,WeakMap,Set,WeakSet等,并且都是iterable的,可以用spread操作符和for...of语法遍历。这些数据结构在其他语言中早就有了,使用起来也非常方便,这篇文章从Map讲起。规范的23.1章节定义了Map以及相关的API,有兴趣的自己去看。
 
有人会说JS中的Object实质上不就是个Map吗?没错,但Object有个问题就是它的key都是字符串,ES6中也可以用Symbol做key。但Map没有这个限制,key可以是任意类型。
 
 
1)构造函数Map ( [ iterable ] )
 
 
 
    let map = new Map([  
    [ 1, 'one' ],  
    [ 2, 'two' ],  
    [ 3, 'three' ]  
    ]);  
 
 
2)Map.prototype.get ( key )
 
如果集合中有key,返回value,否则返回undefined
 
 
 
    let map = new Map();  
    const KEY1 = {};  
    map.set(KEY1, 'hello');  
    console.log(map.get(KEY1)); // hello  
    console.log(map.get(0));//undefined  
 
 
3)Map.prototype.set ( key , value )
 
给Map设置值,如果已经存在key,则更新value,如果不存在key,创建一条记录。返回本身,可以链式操作
 
 
 
    let map = new Map()  
    .set(1, 'one')  
    .set(2, 'two')  
    .set(3, 'three');  
 
 
4)Map.prototype.has ( key )
 
检查Map是否存在key,存在返回true,不存在返回false
 
5)Map.prototype.delete ( key )
 
删除key对应的记录,如果存在key,返回true,否则返回false
 
 
6)Map.prototype.clear ( )
 
清空所有记录
 
 
7)Map.prototype.entries(),Map.prototype.keys(),Map.prototype.values()
 
用过Java Map的人肯定对这些不陌生。返回的依次是:所有记录,键,值,都是可以iterable的。但注意返回的不是个数组。
 
 
 
    var map = new Map();  
    const KEY1 = {};  
    map.set(KEY1, 'hello');  
      
    map.values()[0]//undefined  
    [...map.values()][0]//"hello"  
 
 
8)Map.prototype.size
 
返回记录数,回调参数为value,key,map
 
 
9)Map.prototype.forEach
 
不多说了,谁都会用
 
 
最后我们要弄清一个问题,Map的key是如何确定唯一性的。看规范Map章节的一开始就有个描述:
 
Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values. A distinct key value may only occur in one key/value pair within the Map’s collection. Distinct key values are discriminated using the SameValueZero comparison algorithm.
 
 
继续看SameValueZero的定义,规范7.2.10章节SameValueZero(x, y):
 
1. ReturnIfAbrupt(x).
2. ReturnIfAbrupt(y).
3. If Type(x) is different from Type(y), return false.
4. If Type(x) is Undefined, return true.
5. If Type(x) is Null, return true.
6. If Type(x) is Number, then
    a. If x is NaN and y is NaN, return true.
    b. If x is +0 and y is -0, return true.
    c. If x is -0 and y is +0, return true.
    d. If x is the same Number value as y, return true.
    e. Return false.
7. If Type(x) is String, then
    a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices) return true; otherwise, return false.
8. If Type(x) is Boolean, then
    a. If x and y are both true or both false, return true; otherwise, return false.
9. If Type(x) is Symbol, then
    a. If x and y are both the same Symbol value, return true; otherwise, return false.
10. Return true if x and y are the same Object value. Otherwise, return false.
 
 
简单来看和全等===差不多,只不过NaN是等于NaN,并且正0和负0也相等
 
 
*以上全部代码在Chrome 47下通过测试
 
 
 
版权声明:欢迎转载,乐于分享 https://blog.csdn.net/qq_28506819/article/details/71037206 
为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权