Set与WeakSet类型在JavaScript中的使用
set类型与array与object对比分析:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <style> </style> </head> <body> <script> // let arr = [1, 1, 1, 1, 1]; // console.table(arr); // set集合 // let set = new Set([1, 2, 3, 4, 5]); // console.log(set); // 区分类型,相同类型的不可重复 // let set = new Set(); // set.add(1); // set.add(1); // set.add('1'); // console.log(set); // set和object的区别 // 对象中:不同类型可隐式转换的也不可重复,否则前面的会被后面的覆盖 // let obj = { // 1: 'cyy1', // '1': 'cyy2' // }; // console.log(obj); let obj = { 1: 'cyy1', '1': 'cyy2' }; // let cyy = { // obj: 'yaya' // }; // console.log(cyy.obj); // 变量需要用方括号 let cyy = { [obj]: 'yaya' }; // 对象作为属性名,会自动调用toString(),转为字符串 console.log(cyy);//[object Object] console.log(obj.toString()); console.log(cyy[obj.toString()]); </script> </body> </html>
set元素检测与管理:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <style> </style> </head> <body> <script> // let set = new Set('cyy'); // console.log(set); // 字符串会转数组,且不可重复;相当于以下写法 // let set = new Set([...'cyy']); // console.log(set); //通常还是用数组形式 // 获取set长度 let set = new Set([1, 2, 3]); console.log(set.size); // 判断set是否含有某个值 console.log(set.has(1)); console.log(set.has(11)); // 删除set中的某个值 set.delete(2); console.log(set); // 获取set的值 console.log(set.values()); // 清空set set.clear(); console.log(set.size); </script> </body> </html>
类型之间互相帮助才是好兄弟:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <style> </style> </head> <body> <script> // set转数组 // let set = new Set([1, 2, 3, 4]); // console.log(Array.from(set)); // console.log([...set]); // let set = new Set('123456789'); // let res = [...set].filter((item) => item < 5); // console.log(new Set(res)); // 通过set帮助array去重 let arr = [1, 2, 3, 5, 2, 4, 1]; console.log([...new Set(arr)]); </script> </body> </html>
遍历set类型的方式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <style> </style> </head> <body> <script> // set没有键名,key和value都是键值 // let set = new Set([11, 22, 33, 44]); // console.log(set.keys()); // console.log(set.values()); // console.log(set.entries()); let set = new Set([11, 22, 33, 44]); // set.forEach(function (value, index, arr) { // console.log(value, index, arr); // }); for (let value of set) { console.log(value); } </script> </body> </html>
使用set处理网站关键词:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> body { padding: 200px; } ul { list-style: none; padding: 0; margin: 0; } li { padding: 10px; border: 1px solid #ddd; } </style> </head> <body> <input type="text" name="keyword"> <ul></ul> <script> // let obj = { // data: new Set(), // set keyword(value) { // this.data.add(value); // }, // show() { // let ul = document.querySelector('ul'); // ul.innerHTML = ''; // this.data.forEach(function(value) { // ul.innerHTML += `<li>${value}</li>`; // }); // } // } // let input = document.querySelector('[name=keyword]'); // input.addEventListener('blur', function() { // obj.keyword = this.value; // obj.show(); // }); let obj = { data: new Set(), keyword(value) { this.data.add(value); }, show() { let ul = document.querySelector('ul'); ul.innerHTML = ''; this.data.forEach(function(value) { ul.innerHTML += `<li>${value}</li>`; }); } } let input = document.querySelector('[name=keyword]'); input.addEventListener('blur', function() { obj.keyword(this.value); obj.show(); }); </script> </body> </html>
并集-交集-差集,算法实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> let a = new Set([1, 2, 3, 4, 5]); let b = new Set([4, 5, 9, 6]); // 并集 console.log(new Set([...a, ...b])); // 差集,a有,b没有 console.log(new Set([...a].filter(function(item) { return !b.has(item); }))); </script> </body> </html>
WeakSet语法介绍:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <div></div> <div></div> <script> // WeakSet 跟 set 差不多,但是WeakSet的元素只能是引用类型 // let set = new WeakSet([1, 2]); // let set = new WeakSet(); // set.add([1, 2, 3]); let nodes = new WeakSet(); let divs = document.querySelectorAll('div'); divs.forEach(function(item) { // console.log(item); // WeakSet的元素可以是dom节点 nodes.add(item); }); console.log(nodes); // 删除元素 nodes.delete(divs[0]); // nodes.delete(nodes[1]); console.log(nodes); // 判断是否含有元素 console.log(nodes); console.log(nodes.has(divs[0])); console.log(nodes.has(divs[1])); </script> </body> </html>
引用类型的垃圾回收原理:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <div></div> <div></div> <script> let a = { name: 'cyy' }; let b = a; let arr = [a]; //被引用第三次 arr[0] = null; //解除该引用 // 此时该内存地址被a引用一次,被b引用一次,共引用2次 a = null; console.log(b); // 次数a的引用断开,该内存地址只被b引用1次 b = null; // 此时该内存地址没有被引用,因此属于垃圾 console.log(a, b); //系统会自动检测内存有没有被引用,没有的话会自动垃圾回收 </script> </body> </html>
WeakSet弱引用类型:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // WeakSet是弱引用类型,因此无法使用keys,values,以及迭代方法 // WeakSet不会增加引用次数 // let a = { // name: 'cyy' // }; // let b = a; // let set = new WeakSet(); // set.add(a); // // 此时该内存被引用次数为2, // a = null; // b = null; // // 此时该内存没有被引用,但是WeakSet并不知情,导致WeakSet内显示空元素 // console.log(set); // WeakSet的弱引用特性会导致循环出问题,因此无法进行循环操作 // console.log(set.keys()); // console.log(set.values()); // let set = new WeakSet(); // set.add([1, 2, 3]); // console.log(set.keys()); // console.log(set.values()); // for (const item of set) { // console.log(item); // } // console.log(set.size); let a = { name: 'cyy' }; let b = a; let set = new WeakSet(); set.add(a); a = null; b = null; console.log(set); // WeakSet在一定时间之后,也是能够读取到被回收的垃圾,然后同步清空 setTimeout(function() { console.log(set); }, 2000); </script> </body> </html>
todo任务列表中使用WeakSet:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> * { margin: 0; padding: 0; } body { padding: 200px; } ul { list-style: none; } li { width: 200px; border: 1px solid orange; position: relative; height: 40px; line-height: 40px; margin-bottom: 10px; padding: 10px; } li a { display: inline-block; color: white; position: absolute; right: 5px; top: 15px; background: green; border-radius: 5px; width: 30px; height: 30px; line-height: 30px; text-align: center; text-decoration: none; } li.remove { opacity: .1; } </style> </head> <body> <ul> <li>baidu.com <a href="javascript:;">x</a> </li> <li>google.com <a href="javascript:;">x</a> </li> <li>taobao.com <a href="javascript:;">x</a> </li> </ul> <script> class Todo { // 构造函数 constructor() { this.items = document.querySelectorAll('li'); // console.log(this.items); this.lists = new WeakSet(); // 只能用箭头函数,因为this指向不能变 this.items.forEach((item) => this.lists.add(item)); console.log(this.lists); } run() { this.addEvent(); } addEvent() { this.items.forEach((item) => { let a = item.querySelector('a'); // 只能用箭头函数,因为this指向不能变 a.addEventListener('click', (e) => { // console.log(e.target); let li = e.target.parentElement; if (this.lists.has(li)) { li.classList.add('remove'); this.lists.delete(li); } else { // 提示已删除 // alert('todo已经删除'); // 恢复被删除的 li.classList.remove('remove'); this.lists.add(li); } }) }) } } new Todo().run(); </script> </body> </html>