首頁  >  文章  >  web前端  >  ES6新特性-JavaScript中Set和WeakSet類型的資料結構的程式碼詳細介紹

ES6新特性-JavaScript中Set和WeakSet類型的資料結構的程式碼詳細介紹

黄舟
黄舟原創
2017-03-07 14:15:211275瀏覽

ES6提供了新的資料結構 SetSet物件不是數組,可以用來保存物件或基本類型, 所有保存的值都是唯一的, chrome瀏覽器>38和FF>13,以及nodeJS,對Set支援良好, 以下的一些程式碼,都可以拷貝到控制台直接運行哦;

建立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]這個玩意兒…. )

使用陣列模擬一個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>

輸出:

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

以下這種程式碼更短,太酷了啊, 這個方法來自: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}

弱引用的

WeakSet

##WeakSet

物件是一些物件值的集合, 並且其中的每個物件值都只能出現一次,WeakSet只能存物件類型的元素,例如:ObjectArray Function 等等;有了弱引用的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###裡面的該節點如果不存在別的引用的話, 一段時間內會被記憶體回收;###### 以上就是ES6新特性-JavaScript中Set和WeakSet類型的資料結構的程式碼詳細介紹的內容,更多相關內容請關注PHP中文網(www.php.cn)! ########## ###
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn