ES6新特性:JavaScript中Set和WeakSet型別的資料結構
ES6提供了新的資料結構Set,Set物件不是陣列, 可以用來儲存物件或者基本型別, 所有儲存的值都是唯一的, 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只能存物件型別的元素,比如:Object, Array, 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裡面的該節點如果不存在別的引用的話, 一段時間內會被記憶體回收;
參考:
MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
ruanyifeng:http://es6.ruanyifeng.com/#docs/set-map
相關文章
- JavaScript Set與WeakSetJavaScript
- ES6之Set和Map資料結構資料結構
- ES6 Set 資料結構資料結構
- ES6【Set 、 WeakSet 、Map、WeakMap 】
- ES6 Set,WeakSet,Map,WeakMap
- 【ES6基礎】Set 與 WeakSet
- ES6的Set和Map資料結構,由你製造資料結構
- JavaScript中的樹型資料結構JavaScript資料結構
- javascript ES6 新特性之 解構JavaScript
- Set和Map資料結構。資料結構
- javascript中的資料型別JavaScript資料型別
- JS 中普通物件資料型別的基本結構和操作JS物件資料型別
- 深入理解JavaScript中的WeakMap和WeakSetJavaScript
- JavaScript 中的 資料結構JavaScript資料結構
- 前端-JavaScript新特性(ES6)前端JavaScript
- ES6中let 和 const 的新特性
- ES6中的新特性:Iterables和iterators
- 資料結構中抽象資料型別是什麼?資料結構抽象資料型別
- JavaScript中的資料型別-儲存差別JavaScript資料型別
- ES6新特性總結之解構賦值和字串模板賦值字串
- python資料結構setPython資料結構
- 資料結構中樹和森林的區別資料結構
- JavaScript資料型別轉換總結JavaScript資料型別
- javaScript的資料型別JavaScript資料型別
- Python中資料結構與特性Python資料結構
- Stack and Queue in JavaScript(Javascript中的資料結構之棧和佇列)JavaScript資料結構佇列
- ES6新特性總結
- 07 redis-資料型別 setRedis資料型別
- Redis 基本資料型別(Set) 的操作命令Redis資料型別
- js資料結構--集合(set)JS資料結構
- ES6 系列之模擬實現一個 Set 資料結構資料結構
- JavaScript - 資料型別JavaScript資料型別
- JavaScript 資料型別JavaScript資料型別
- JavaScript資料型別JavaScript資料型別
- JAVA中基本資料型別和引用資料型別Java資料型別
- 【Tensorflow_DL_Note4】Tensorflow中的常量、變數和資料型別的結構變數資料型別
- JavaScript 的資料結構和演算法JavaScript資料結構演算法
- javascript中的資料型別及其常見用法JavaScript資料型別
- JavaScript中的程式結構和分支結構JavaScript