Home >Web Front-end >JS Tutorial >ES6 new features - detailed code introduction to Set and WeakSet type data structures in JavaScript

ES6 new features - detailed code introduction to Set and WeakSet type data structures in JavaScript

黄舟
黄舟Original
2017-03-07 14:15:211329browse

ES6 provides a new data structure Set. The Set object is not an array and can be used to save objects or basic types. All saved values ​​are The only, chrome browser>38 and FF>13, as well as nodeJS, have good support for Set. Some of the following codes can be copied to the console and run directly;

The basic method of creating a Set instance is:

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

Or like this:

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

As you can see, the repeated 4 above is only saved in set One, so the Set object can be used to deduplicate the array;

Set can also be used to save NaN and undefined. If there are duplicate NaNs, Set will think that there is only one NaN(Actually NaN!=NaN);

Objects after instance Set have these properties and methods:

Properties

Set.prototype
Set.prototype.size

Method

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

SetIn fact, we can directly simulate this type of data structure with an array Although it cannot be compared with the original one, it can only simulate some of the methods and properties in the above list (there are also some functions that cannot be realized, the [Symbol.species] of the Set instance points to itself , but there is no such thing as [Symbol.species] in chrome...)

Use an array to simulate a Set constructor:

<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>

Attributes of the Set instance:

size attribute :size refers to the length of this Set, which has the same effect as the length of the array."
constructor attribute: This attribute points to the Set constructor, and this code can be implemented (new Set).constructor === Set //Output: true

Methods of Set instance:

add method, add data to the set;

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

clear method, clear the data in the set;

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

delete Method, delete the specified data in the set:

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

entries method:

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

forEach method: set's forEach has two parameters, the first parameter is a function, and the second parameter is a non- Necessary, if the second parameter is passed, then the context this of the function is the second parameter we pass:

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

Output:

has method, has is to determine whether this set has a specified value, and returns false or true;

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

keys method and values() method, both methods return an iterator;

<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() method, @iterator method is the default iterator of 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>

In fact, we can override set[Symbol.iterator], but it will not generate the keys and values ​​methods of set Impact;

The entire 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()方法,手动去获取每一个值;

The actual use of Set:

Use set to conveniently perform intersection and union:

Find the union, We can give two solutions or more:

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)));
}

This way of obtaining intersection is similar to finding the intersection of arrays;

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;
};

The following code is shorter, so cool, this Method from: http://es6.ruanyifeng.com/#docs/set-map;

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}

Weak referenceWeakSet

WeakSet An object is a collection of object values, and each object value can only appear once. WeakSet can only store elements of object type, such as: Object, Array , Function and so on; with the weak reference WeakSet, you don’t have to worry about memory leaks. If other objects do not reference the object, the object will be garbage collected. Automatic recycling;

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

The WeakSet object has only three methods, and the WeakSet object has no size attribute;

  • ##weakSet.add();

  • weakSet.delete();

  • ##weakSet.has();

  • If the object does not have a reference, the WeakSet object will recycle the memory occupied by the object without reference. You can run the demo below, and then after a while (my chrome browser
You will see the effect in 10S

) Look at the console again:

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

weakSet

can be used to save DOM nodes. When the node is deleted, weakSet inside If there are no other references to this node, it will be recycled by memory within a period of time; The above is a detailed introduction to the code of the new features of ES6 - Set and WeakSet type data structures in JavaScript, and more related content Please pay attention to the PHP Chinese website (www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn