澳门新葡萄京官网注册 1

ES6新特性:JavaScript中Set和WeakSet类型的数据结构

ES6提供了新的数据结构SetSet对象不是数组,
可以用来保存对象或者基本类型, 所有保存的值都是唯一的,
chrome浏览器>38和FF>13,以及nodeJS,对Set支持良好,
以下的一些代码,都可以拷贝到控制台直接运行哦;

ES6中如何使用Set和WeakSet,es6setweakset

ES6中提供了两新数据结构-Set和WeakSet。Set是类似于数组,但是成员变量的值都是唯一的,没有重复的值。WeakSet也是不重复的值的集合,但是只能用来存放对象。

一、Set使用

(1)Set本身提供了一个构造函数,用来生成Set数据结构。

var s = new Set();
[2,2,2,5,8,16,2,1].map(x => s.add(x))

for(i of s){console.log(i)}
//2,5,8,16,1

(2)Set()函数可以接受一个数组,作为构造参数,用于做初始化。

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

注意:向Set中加入值的时候不会发生类型转换,所以5和”5”是两个不同的值,Set内部判断两个值是否相等,使用的是
===,这就意味着这两个对象总是不相等。唯一列外的是NaN本身(精确相等运算符认为NaN不等于自身)

let set = new Set();
set.add({})
set.size//1
set.add({})
set.size//2

澳门新葡萄京官网注册,则,上面的代码表示,由于这两个空对象不是精确相等,所以是两个不同的值。

(3)Set的方法和属性

(3.1)Set的属性

Set.prototype.size:返回Set实例的成员数量。
Set.prototype.constructor:默认的构造Set函数。

(3.2)Set的操作啊函数

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

var set = new Set();
set.add(1).add(2).add(22).add(22);
set.size//3

set.hae(22)//true
set.has(4)//false
set.delete(2)//true

(3.3)Set遍历操作

Set有四个遍历方法。可以用于遍历成员。
keys() :返回一个键名的遍历器
values() :返回一个值的遍历器
entries() :返回一个键值对的遍历器
forEach():使用回调函数遍历每个成员

注意:由于Set没有键名,只有值名,keys()和values()返回的结果是一样,

let set = new Set(['red','green','blue']);
for(let item of set.keys()){
console.log(item);
}
//red,green,blue
for(let item of set.values()){
console.log(item);
}
//red,green,blue
for(let item of set.entries()){
console.log(item);
}
//["red","red"]
//["green","green"]
//["blue","blue"]

//所以,entries方法返回的遍历器同时包括键名和值,所以每次输出的是一个数组。其实成员都是完全一样的。

注意:Set默认的可遍历,其默认遍历器生成函数就是它的values方法。
这就意味着,可以省略values方法,直接用for…of遍历。

var set = new Set([1,2,3,4]);
for(let x of set){
console.log(x);
}
//1
//2
//3
//4

如果使用扩展运算符(…)内部使用for…of 循环,所以也可以用于Set结构。

let set = new Set(['red','green','blue']);
let arr = [...set];
//['red','green','blue'];

(3.4)Set实现并集,交集,差集

let set1 = new Set([1,2,3,4,5,6]);
let set2 = new Set([4,5,6,7,8,9]);

//并集
let union = new Set([...set1,...set2]);
//[1,2,3,4,5,6,7,8,9]
//交集
let intersect = new Set([...set1].filter(x => b.has(s)));
//[4,5,6]
//差集
let intersect = new Set([...set1].filter(x => !b.has(s)));
//[1,2,3,4]

(3.5)Set实现forEach的使用

let set = new Set([1,2,3,4,5,6]);
set.forEach(value,key)=>consloe.log(vlaue+1);
//2
//3
//4
//5
//6
//7

注意:forEach方法的参数就是一个处理函数,该函数依次为(键值,键名)集合本身。另外,forEach方法还有第二个参数,表示绑定this的对象。

二、WeakSet使用

WeakSet类似于Set,也是不重复的值的集合。但是它只能用于存储对象。而不能是其他类型的值。
WeakSet是一个个构造函数。可以接受数组和类似数组的对象作为参数。(实际上,任何具作为iterable接口的对象都可以作为WeakSet的参数)。该数组的所有成员都会自动成为WeakSet的实例对象的成员。
var a = new [[1,2],[3,4]];
var ws = new WeakSet(a);

var ws = new WeakSet();
ws.add(1);//TypeError:Invalid value used in weak set 
ws.add(Symbol);//TypeError:Invalid value used in weak set 

添如一个数值和一个Symbol,结果同时报错。

WeakSet结构有以下的上方法
WeakSet.protoptype.add(value):向WeakSet实例添加一个新成员。
WeakSet.protoptype.delete(value):删除WeakSet实例指定成员。
WeakSet.protoptype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例中。

var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window);//true
ws.has(foo);false
ws.delete(window);//true
ws.has(window);//false

WeakSet
不能遍历,是因为成员都是弱引用,随时可能消失,遍历不能保证成员的存在。可能刚刚遍历结束,成员就取不到了。WeakSet的一个用处是存储DOM节点,而不用担心这些节点从文档移除时,会引起内存的泄露。

创建Set实例的基本方法为:

let set = new Set(); //或者 new Set(null);
console.log(set);

或者这样:

let set = new Set([1,2,3,4,4,4,4,4]);
console.log( Array.from(set) ); //输出:[ 1, 2, 3, 4 ]

可以看到,以上重复的4,在set里面只保存了一个,
所以Set对象可以用来给数组去重;

Set也能用来保存NaN和undefined, 如果有重复的NaN,
Set会认为就一个NaN(实际上NaN!=NaN);

实例Set以后的对象拥有这些属性和方法

属性

Set.prototype
Set.prototype.size

方法

Set.prototype.add()
Set.prototype.clear()
Set.prototype.delete()
Set.prototype.entries()
Set.prototype.forEach()
Set.prototype.has()
Set.prototype.values()
Set.prototype[@@iterator]()

Set这种类型的数据结构其实我们可以直接用数组模拟出来,
虽然不能和原生的比, 只能模拟以上列表的一些方法属性(
还有一些功能无法实现的 , Set实例的[Symbol.species]指向自己,
但是chrome中没有[Symbol.species]这个玩意儿…. )

您可能感兴趣的文章:

  • 详解JavaScript ES6中的Generator
  • 详解JavaScript ES6中的模板字符串
  • 解析JavaScript的ES6版本中的解构赋值
  • 跟我学习javascript的最新标准ES6
  • 深入浅析react native es6语法
  • ES6的新特性概览
  • ES6中非常实用的新特性介绍

ES6中提供了两新数据结构-Set和WeakSet。Set是类似于数组,但是成员变量的值都是唯一的,没有重复的值…

使用数组模拟一个Set构造器:

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<script>
    "use strict";
    class Set {
        //对_set进行去重;
        static refresh () {
            let _this = this;
            let __set = []
            this._set.forEach(function(obj) {
                if( __set.indexOf(obj) === -1 && obj!=undefined) {
                    __set.push(obj);
                }
            });
            _this._set =__set;
            this.size = _this._set.length;
        }
        constructor(arg) {
            this.size = 0;
            this[Symbol.species] = this;
            this._set = Array.isArray(arg)&&arg||[];
            Set.refresh.call(this)
        }
        add (obj) {
            this._set.push(obj);
            Set.refresh.call(this)
            return this;
        }
        clear () {
            this._set.length = 0;
            return this;
        }
        delete (obj) {
            if( this._set.indexOf(obj)!=-1 ) {
                this._set[this._set.indexOf(obj)] = undefined;
            };
            Set.refresh.call(this);
            return this;
        }
        /**
         * @desc
         * @return Entries [[],[],[],[]]
         * */
                entries () {
            let result = [];
            this.forEach(function(key, value) {
                result.push([key,value]);
            });
            return result;
        }
        has () {
            if( this._set.indexOf(obj)!=-1 ) return true;
        }
        keys () {
            return this[Symbol.iterator]();
        }
        values () {
            return this[Symbol.iterator]();
        }
        //直接使用数组的forEach方便啊;
        forEach (fn, context) {
            let _this = this;
            this._set.forEach((value) => fn.call(context||value, value, value, _this) );
        }
        //必须支持生成器的写法;
    *[Symbol.iterator] (){
        let index = 0;
        let val = undefined;
        while(index<this.size) {
        val = this._set[index];
        yield  val;
        index++;
    }
    }
    }
    var set = new Set([0,0]);
    //对Set进行基本的操作;
    set.add(1).add(2).add(3).add({1:1})
    set.delete(1);
    set.add(1);
    //使用Set的forEach方法;
    set.forEach(function(key,value,s){console.log(key,value,s,"this")},{this:"this"})
    //检测生成器是否正常运行;
    for(let s of set) {
        console.log(s)
    }
    //因为这个对象有Symbol.iterator, 所以使用扩展符也是好使的;
    console.log([...set]);
</script>
</body>
</html>

Set实例的属性:

size属性:size是指这个Set的长度,和数组的length效果一样的”
constructor属性: 这个属性指向Set构造函数 ,这个代码即可实现 (new
Set).constructor === Set //输出:true

Set实例的方法:

add方法,往set添加数据;

<script>
    Array.from((new Set([1,2])).add(3)); // 输出:[1, 2, 3]
</script>

clear方法,把set里面的数据清空;

let set = (new Set([1,2,3,4]));
set.clear();
Array.from(set);

delete方法,删除set里面的指定数据:

let set = (new Set([1,2,3,4]));
set.delete(1);
Array.from(set); //输出:[2, 3, 4]

entries方法:

let set = (new Set([1,2,3,4]));
Array.from(set.entries());

forEach方法:set的forEach有两个参数,
第一个参数为一个函数,第二个参数是非必须的,如果传了第二个参数,
那么该函数的上下文this就是我们传的第二个参数:

<script>
let set = (new Set([1,2,3,4]));
set.forEach(function() {
    console.log(arguments);
    console.log(this)
},"1111");
</script>

输出:

澳门新葡萄京官网注册 1

has方法, has是判断这个set是否有指定的值, 返回false或者true;

<script>
let set = (new Set([1,2,3,4]));
console.log(set.has(1)) //输出:true;
console.log(set.has(5)) //输出:false
</script>

keys方法和values()方法, 这两个方法都是返回一个迭代器;

<script>
let set = new Set([1,2,3,4]);
console.log(set.keys());
console.log(set.values());

var keys = set.keys();
for(let key of keys) {
    console.log(key);
};
</script>

@@iterator()方法, @iterator方法是set默认的迭代器;

<script>
let set = new Set([1,2,3,4]);
let setIner = set[Symbol.iterator]();
console.log(setIner.next().value) //输出:1
console.log(setIner.next().value) //输出:2
console.log(setIner.next().value) //输出:3
console.log(setIner.next().value) //输出:4
</script>

实际上我们可以重写set[Symbol.iterator],但是不会对set的keys和values方法产生影响;

整个DEMO:

var mySet = new Set();
//往mySet里面添加数据, 1 , 5
mySet.add(1);
mySet.add(5);
mySet.add("some text");
//添加对象
var o = {a: 1, b: 2};
mySet.add(o);

mySet.has(1); // 返回:true
mySet.has(3); // 返回:false
mySet.has(5);              // 返回:true
mySet.has(Math.sqrt(25));  // 返回:true
mySet.has("Some Text".toLowerCase()); // t返回:rue
mySet.has(o); // 返回:true

mySet.size; // 4

mySet.delete(5); // 从mySet里面删除5
mySet.has(5);    // 输出:false, 5 已经被删除了

mySet.size; // 现在的长度为:3

// 通过 for...or循环获取数据;
// 输出: 1, "some text"
for (let item of mySet) console.log(item);

// 输出: 1, "some text"
for (let item of mySet.keys()) console.log(item);

// 输出: 1, "some text"
for (let item of mySet.values()) console.log(item);

// 输出: 1, "some text", 对于Set来说:key和value是一样的
for (let [key, value] of mySet.entries()) console.log(key);

// 把迭代器转化为数组的第一种方式;
var myArr = [v for (v of mySet)]; // [1, "some text"]
// 把迭代器转化为数组的第二种方式;
var myArr = Array.from(mySet); // [1, "some text"]
// 也可以用next()方法,手动去获取每一个值;

Set的实际用处:

利用set可以方便的进行交集和并集:

求并集, 我们可以给两个方案或者更多:

var union = (setA, setB) => {
    //[...setA]这种方式目前只有babel才支持
    return new Seet([...setA,...setB]);
};
var union = (setA, setB) => {
    return new Set(Array.from(setA).concat(Array.from(setB)));
}

这种获取交集的方式,和数组求交集差不多;

var intersect = (set1, set2) => {
    //return [x for (x of set1) if (set2.has(x))]; 这种写法完全不行嘛....
    var resultSet = new Set();
    for(let set of set1) {
        if(set2.has(set)) {
            resultSet.add(set);
        };
    };
    return resultSet;
};

以下这种代码更短,太酷了啊,
这个方法来自:;

var intersect = (set1, set2) => {
    return new Set([...set1].filter(x => set2.has(x)));
}
console.log(intersect(new Set([1,2,3,4]), new Set([2,3,4,5]))); //输出:Set {2,3,4}

弱引用的WeakSet

WeakSet对象是一些对象值的集合,
并且其中的每个对象值都只能出现一次,WeakSet只能存对象类型的元素,比如:ObjectArrayFunction 等等;有了弱引用的WeakSet
就不用担心内存泄漏了,如果别的对象不引用该对象,
这个对象会被垃圾回收机制自动回收;

<script>
    console.log(new WeakSet([{},[],()=>({1:1})]));
</script>

WeakSet对象的方法只有三个,而且WeakSet对象没有size属性;

  • weakSet.add();
  • weakSet.delete();
  • weakSet.has();

如果对象不存在引用, 那么WeakSet对象会把没有引用的对象占用的内存回收,
下面这个demo,你可以跑一下,
然后过一会儿(我的chrome浏览器10S就看到效果了)再看控制台:

<script>
var ws = new WeakSet()
var obj = {}; ws.add(obj);
ws.add([])
setInterval(()=>{
    console.log(ws);
},1000)
</script>

weakSet可以用来保存DOM节点,
当节点被删除, weakSet里面的该节点如果不存在别的引用的话,
一段时间内会被内存回收;

参考:

MDN:

ruanyifeng:

发表评论

电子邮件地址不会被公开。 必填项已用*标注