ECMAscript6 中Set数据结构

作者: Ziksang | 来源:发表于2017-01-30 12:04 被阅读128次

    大家好混元霹雳手Ziksang又来了,给大家讲讲es6,Set这个新的数据结构

    大年初三,先给大家拜个年,我知道我的拜方式错了!!红包即将打到你的支付宝中,请接收!

    2017年的目标就是把ecmscript6所有的知识点全弄明白,我相信以后会基于ecmascript6的新特性肯定会出一些更牛B的框架,就像vue一样用了Object.defineProperty ecmascript5的新特性来进行数据劫持,所以我很期待

    简单介绍一下吧

    Set基本介绍

    Set是ES6中数据结构中其中一个新的特性,我们看上去往往很像数组,但是他的每个成员都是唯一的,不会存在重复的值

    Set也是一个构造函数,用来生成Set这个数据结构,我们可以看看他实例原型上有那些东西,简单看一下

    在set原型上放了这么多方法,接下来我一一介绍一下吧,记住学习一定要学到根本!!!!

    注意我的每一步代码都是自上而下有着关联的

    add方法

    let set = new Set()
    let array = [1,"ziksang",3,3,true,5,5]
    array.forEach(item => {
            set.add(item)
    })
    console.log(set)
    // Set {1, "ziksang", 3, true, 5}
    

    1.先new出set这个构造函数实列,我们存在set变量上
    2再声明一个array这个数组,里面的数组成员有各种数据类型和重复的值
    3.用Set原型上add方法把用es5中each方法把每个值添加到set成员里
    4.打印出来是一个对象,里面相同类型相同值都会去掉,但是里面的整体结构和类组数对象一样,有着自己的长度

     for (let i of set) {
             console.log(i);
             console.log(typeof i)
    }
    

    以上我们再次用for of的方法也,同样也是es6的新特性,此时就可以把set对象里每一个值可以打印出来,里面的打印出的每一个数据类型也同样是我们array数组里定义的数据类型


    上面代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。
    Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。

            function demo(){
                let set = new Set(arguments)
                console.log(set)
            }
            demo(1,2,4,4,5)
            //Set {1, 2, 4, 5}
            let set = new Set([1,2,4,4,5])
            console.log(set)
            //Set {1, 2, 4, 5}
    

    1.Set函数里我们可以接受参数来作为初始化跟new Array[1,2,3,4]性质是一样的
    2.第一个我在demo函数里让set函数接收了demo里arguments对象作为参数
    3.第二个我直接在set函数里放入一个数组
    4.两都console.log()打印出来的是一样的,同样不会包含同类型同样的值的成员

    size方法

    size方法是用来判断出,set里成员的个数

    var items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
    items.size // 5
    

    1.虽然上面我定义了8个成员数量,但是最后个数只有5个,因为还是同样的不会把重复同类型同样的值算进去,只算一个

    数组去重方法
    在以前数我面试的时候别人一直接我数组去重怎么样,我现在只想回答他,看下面

           let array = [1,2,2,3,3,4]
           let set = new Set(array)
           array = [...set]
           console.log(array)
          //[1,2,3,4]
    

    1.声明一个数组
    2.把数组作为set构造函数的初始化成员
    3.再把set用[...set]来重新复制给array//简称拓展运算符...
    4.扩展运算符(...)内部使用for...of循环,所以也可以用于Set结构。

    关于类型转换,NaN,object的区别

    在往set数据结构中添加值的值,并不会发生类型转换,4和“4”不同的数据类型不会发生转换,他的内部是用Same-value equality,也就是跟恒等差不多,但是NaN不一样很特殊

           console.log(NaN === NaN) //false
           const a = NaN;
           const b = NaN;
           const c = "1";
           const d = 1;
           let set = new Set()
           set.add(a)
           set.add(b)
           set.add(c)
           set.add(d)
           console.log(set) //Set {NaN, "1", 1}
    

    1.如果单纯的比对NaN === NaN肯定是不相等的,但是在set数据结构中,里面的计算原理是把NaN看成相等的


    对于两个对象来说,无是里面是否有值 ,可者有什么样的值都是不相等的,空对象也不相等

           let set = new Set()
           set.add({})
           set.add({})
           console.log(set)  //Set {Object {}, Object {}}
           console.log(set.size)//2
    

    1.可以看出空对象是不相等的,所以它们被视为两个值。总个数依然是2个


    Set实例的属性和方法,也就是Set构造函数上定义的方法和属性

    Set结构的实例有以下属性。
    Set.prototype.constructor:构造函数,默认就是Set函数。
    Set.prototype.size:返回Set实例的成员总数。

    Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

    add(value):添加某个值,返回Set结构本身。
    delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    has(value):返回一个布尔值,表示该值是否为Set的成员。
    clear():清除所有成员,没有返回值。

    size和add我在前面已经讲过了,再少许提一下吧

            let set = new Set()
            set.add(3).add(2).add(2).add("ziksang");
            console.log(set)//set{3,2,ziksang}
            console.log(set.has(3)) //true
            console.log(set.delete(2))  //true
            console.log(set)   //set{3,ziksang}
            console.log(set.clear()) //undefined
            console.log(set) //set{}
    

    1.我们new出Set构造函数的实列对象进行一个一个add进行添加,但是添加了两个同类型同样值 的2 !最后打印出来同样的一个会被去除
    2.set.has()是进行对set数据结构中成员是否存在的判断
    3.删除set数据结构中成员
    4set.clear()是进行清除所有成员,set实列也因此成为了一个空对象


    不同对比的例子,看看Object和Set两个数据结构判断方式不同

            let obj={
                name : "ziksang",
                age : 22
            }
            let set = new Set(["name",22])
            if(obj.name){
                console.log("在对象里有name这个健值")
            }
            if(set.has("name")){
                console.log("set数据结构中有name这个成员")
            }
    

    提示

    1.[阮一峰]用obj[somename]来判断是否对象里有这个健,打出来是undefined,以上修正了一下
    2.判断set数据结构中是否有某个成员,用set.has()来判断


    另外再介绍一下另一种数组去重方式

    Array.from()是es6数组中新带的一个方法

            function demo(array){
                return Array.from(new Set(array))
            }
            let result = demo([1,1,2,2,3])
            console.log(result)//1,2,3
    

    Array.from是什么鬼以后具体讲到es6数组我给大家讲讲,我现在只知其一,不知其二,讲不透彻的就不给大家讲


    遍历操作
    Set结构的实例有四个遍历方法,可以用于遍历成员。

    keys():返回键名的遍历器
    values():返回键值的遍历器
    entries():返回键值对的遍历器
    forEach():使用回调函数遍历每个成员
    需要特别指出的是,Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用Set保存一个回调函数列表,调用时就能保证按照添加顺序调用。

    keys方法、values方法、entries方法返回的都是遍历器对象,因为set没有健名只有健值 ,所以健名和健值可以说是同一个值 ,keys和values返回的都是同一个值

           let set  = new Set([1,2,3,4])
           for(item of set.keys()){
               console.log(item) //1,2,3,4
           }
           for(item of set.values()){
               console.log(item) //1,2,3,4
           }
           for(item of set.entries()){
               console.log(item) //[1,1],[2,2],[3,3],[4,4]
               console.log(typeof item)//都是object对象
           }
    

    1.keys,values,entries()返回的都是遍历器对象
    2.entries返回的是健值对,因为为健和值都是一样的,所以里面两个也一样,但是返回出来是是一个对象,本值 上是一个类数组对象


    Set结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。第一个张图我也打印出prototype原型上的方法和属性里,里面的symbol.iterator里是values()所以也可以直接for of Set构造函数返回的实例

    Set.prototype[Symbol.iterator] === Set.prototype.values
    // true
    
           let set  = new Set([1,2,3,4])
           for(item of set){
               console.log(item) //1,2,3,4
           }
    

    可以看出我们直接遍历SET实例和调用value()返回的遍历器对象是一样的


    forEach()

    Set结构的实例的forEach方法,用于对每个成员执行某种操作,没有返回值。

           let set  = new Set([1,2,3,4])
           set.forEach(function(value,key){
               console.log(value*key) //1,4,9,16
           })
    
    
    

    上面代码说明了,对set实例里的健和值互乘,其实value和key都是一个值


    数组的map和filter方法也可以用set上

           let set  = new Set([1,2,3])
           set = new Set([...set].map(item => item*2))
           console.log(set) //{2,4,6}
           set2 = new Set([...set].filter(item =>item>3))
           console.log(set2)//{4,6}
    

    给大家解释一下用了那些关键方法
    1[...set]把set实例进行转成数组再用map方法把线个值乘2给返回当作Set函数里的成员
    2.filter方法也是同理,只是对数组 的值 进行筛选再返回


    因此使用Set可以很容易地实现并集(Union)、交集(Intersect)和差集(Difference)。
    1.并集Union

            let a = new Set([1,2,3,4,5])
            let b = new Set([1,2,3,6,7])
            let set = new Set([...a,...b])
            console.log(set) //1,2,3,4,5,6,7
    

    上面把a,b里遍历出来在放入数组,再用set的特性进行去重

    2.交集

            let a = new Set([1,2,3,4,5])
            let b = new Set([1,2,3,6,7])
            let intersect = new Set([...a].filter(x => b.has(x)))
            console.log(intersect) //{1,2,3}
    

    上面是把a进行转化成数组用filter进行过滤,过滤的返回结果是b里面有的值

    差集

            let a = new Set([1,2,3,4,5])
            let b = new Set([1,2,3,6,7])
            let intersect = new Set([...a].filter(x => !b.has(x)))
            console.log(intersect) //{4,5}
    

    上面是把a进行转化成数组用filter进行过滤,过滤的返回结果是b里面没有的值

    如果想在遍历操作中,同步改变原来的Set结构,目前没有直接的方法,但有两种变通方法。一种是利用原Set结构映射出一个新的结构,然后赋值给原来的Set结构;另一种是利用Array.from方法。

    // 方法一
    let set = new Set([1, 2, 3]);
    set = new Set([...set].map(val => val * 2));
    // set的值是2, 4, 6
    
    // 方法二
    let set = new Set([1, 2, 3]);
    set = new Set(Array.from(set, val => val * 2));
    // set的值是2, 4, 6
    

    第一个方法本质上是把set重新进行赋值,先把原先的set里面的成为用[...set]化为数组再用map来进行重新操作再返回给set构造函数的成员

    第二个方法等我弄懂了再告诉大家

    这里我大部分都是按着阮一锋老师的书籍来进行分析,讲的好的我就记录下来,再用更白的话跟大家讲,有些不清楚说的模糊 的地方也更清楚的跟大家解释明白了,接下来我会把阮一锋老师 ES6所有的知识点都给大家搞明白,搞透彻

    相关文章

      网友评论

        本文标题:ECMAscript6 中Set数据结构

        本文链接:https://www.haomeiwen.com/subject/qxkcittx.html