我们还是从一些现有的需求和问题出发,为什么会有set,他的存在是为了解决什么问题?
我们看一个这样的例子,为一个对象添加键值对
1 var obj = Object.create( null ); 2 obj[5] = 'ghostwu'; 3 console.log( obj["5"] ); //ghostwu 4 console.log( obj[5] ); //ghostwu
以null为原型对象,创建一个对象,给对象添加一个数字键5, 在输出的时候,数字键5会自动转换成字符键"5",这样的自动类型转换,会产生很多隐式问题.
1 var obj = Object.create( null ); 2 var key1 = {}; 3 var key2 = {}; 4 obj[key1] = "ghostwu"; 5 console.log( obj[key1] ); //ghostwu 6 console.log( obj[key2] ); //ghostwu
上面这个程序中,空对象在作为键的情况下, 发生类型转换,变成对象对应的字符串 '[object Object]',所以obj[key1]和obj[key2]指向的是同一个引用
obj = { num : 0 } if ( obj.num ) { alert( '存在这个变量' ); }
判断一个对象是否存在某个属性,如果num是非false的值,上面就没有问题,现在num为0,对象是存在num这个值的,但是用if判断的时候,结果就不对了
es6的set集合,就不会产生键的变量类型转换.
set的基本使用方法:
set是一种有序列表,其中含有一些相互独立的非重复的值.
调用new Set()创建Set集合,如果需要为set集合添加值,用add方法, size属性获取集合的元素个数
1 var set = new Set(); 2 set.add( 5 ); 3 set.add( '5' ); 4 console.log( set.size ); //2
5和'5'是两个不同的值
1 var set = new Set(); 2 var key1 = {}; 3 var key2 = {}; 4 set.add( key1 ); 5 set.add( key2 ); 6 console.log( set.size ); //2
key1和key2是两个独立的值,尽管他们都是空对象
添加一个同名的值操作,会被忽略
1 var set = new Set(); 2 set.add( 5 ); 3 set.add( '5' ); 4 set.add( 5 ); //忽略 5 console.log( set.size ); //2
因为set集合的值是非重复的
has(): 检测set集合是否存在某个值:
1 var set = new Set(); 2 set.add( 5 ); 3 set.add( '5' ); 4 console.log( set.has( '5' ) ); //true 5 console.log( set.has( 5 ) ); //true 6 console.log( set.has( 'wu' ) ); //false
delete: 删除某个值, clear:清空set
1 var set = new Set(); 2 set.add( 5 ); 3 set.add( '5' ); 4 5 console.log( set.has( '5' ) ); //true 6 set.delete( '5' ); 7 console.log( set.has( '5' ) ); //false 8 9 console.log( set.has( 5 ) ); // true 10 console.log( set.size ); // 1 11 12 set.clear(); 13 console.log( set.has( 5 ) ); // false 14 console.log( set.size ); // 0
利用set的特性,可以把数组去重复
1 var set = new Set( [ 10, 20, 30, 10, 10, 20, 40 ] ); 2 console.log( set.size ); //4
Set跟数组一样,也支持forEach方法,参数也是一样
1 var set = new Set( [ 'ghostwu', '悟空', '八戒' ] ); 2 set.forEach( function( val, key, cur ){ 3 console.log( key, val, cur ); 4 } );
键与值一样,数组的键是数字索引,这点不同。所以Set不能像用数组索引那样去取值,但是我们可以把Set转换成数组,而且能利用set的非重复特性,把数组去重复
1 var set = new Set( [ 10, 20, 30, 10, 10, 20, 40 ] ); 2 var arr = [...set]; 3 console.log( arr ); // 10, 20, 30, 40
封装成去重复的函数
1 function unique( arr ){ 2 return [...new Set( arr )]; 3 } 4 var arr = [ 'abc', 'ghostwu', 'abc', 'ghostwu' ]; 5 console.log( unique( arr ) ); //abc, ghostwu
应用set的特性,做一个多人抽奖的小程序,确保每一个人抽到的奖项都是唯一的
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <style> 9 #box { 10 300px; 11 height: 100px; 12 line-height: 100px; 13 font-size: 30px; 14 text-align: center; 15 border: 1px solid #aaa; 16 box-shadow: 2px 2px 3px #ccc; 17 } 18 </style> 19 </head> 20 <body> 21 <div id="box"></div> 22 <input type="button" value="小明"> 23 <input type="button" value="小B"> 24 <input type="button" value="小A"> 25 <input type="button" value="小新"> 26 <input type="button" value="小叶"> 27 <script> 28 var aPrize = ['小米', 'iphone5', 'iphone6', 'iphone7', 'iphone8'], 29 aInput = document.querySelectorAll("input"), 30 oBox = document.querySelector("#box"), 31 set = new Set(), rand = null; 32 aInput.forEach((ele, ind, cur) => { 33 ele.flag = false; 34 ele.addEventListener('click', () => { 35 if ( !ele.flag ) { 36 rand = Math.floor(Math.random() * aPrize.length); 37 if (!set.has(rand)) { 38 set.add(rand); 39 } else { 40 while (set.has(rand)) { 41 rand = Math.floor(Math.random() * aPrize.length); 42 if (!set.has(rand)) { 43 set.add(rand); 44 break; 45 } 46 } 47 } 48 oBox.innerHTML = aPrize[rand]; 49 ele.flag = true; 50 ele.value = '您已经抽过了'; 51 } 52 }, ele); 53 }); 54 </script> 55 </body> 56 </html>