Map与WeakMap讲解与选课组件开发

Map与WeakMap

Map类型的特点与创建

想要了解Map,首先来看看对象吧,拿对象做对比来展开对Map的学习。

对于对象来说,对象当中的键只能是字符串!!

let obj = {
            1:'lihuina',
            "1":"lhn"
        }
console.log(obj); //{1: "lhn"}

定义对象时,虽然可以将键定义为数字,但是打印出来只有下面的那一个,上面的数字1会被自动转换为字符串,下面的就把上面的覆盖了

let hd= {
			//这里需要将obj用[]括起来,这样取到的才是我们定义的对象,否则只是一个普通的键名
            [obj]:"baby"
        }
// 要想取到obj里面的值
// 根据打印hd出来的结果,我们需要
console.log(hd["[object Object]"]);
// 或者
console.log(hd[obj.toString()]);

打印出来的结果如图所示
在这里插入图片描述

但是Map,什么都可以作为键名

// Map创建
let map = new Map();
//不管是字符串,函数,对象,数值,都可以作为键名
map.set("name","lihuina");
map.set(function(){},"baby");
map.set({},"jjjj");
map.set(1,"ggggg");

打印出来点开之后的结果,也能更清晰地看出Map是以键值对的方式存在
在这里插入图片描述

Map支持链式操作

例如字符串的链式操作(连续调用方法):

let str = 'abc';
console.log(str.toLowerCase().substr(1,1));

在Map中中的链式操作(例如可以连续向Map中添加键值对)

let map = new Map([['name','lihuina'],['age',18]]);
map.set("sina","xinlang").set("baidu","百度").set("blog","博客");

console.log(map);

在这里插入图片描述


Map增删改查

let map = new Map();
添加元素 set()
let obj = {
        name:"李四"
	};
map.set(obj,'lisi');
map.set('name','lhn');
获取元素 get()
console.log(map.get(obj));
判断是否存在 has()
 console.log(map.has(obj));
删除元素 delete()
console.log(map.delete(obj));
console.log(map);
清空元素 clear()
map.clear();
console.log(map);

遍历Map

let map = new Map([['name','lihuina'],['age',18]]);
map.set("address","jgsu");
获取所有键 keys()
 console.log(map.keys());
获取所有值 values()
 console.log(map.values());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EWPOyiC2-1625990512668)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20210709205455266.png)]

获取所有的键值对 entries()
console.log(map.entries());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FF7mf7Rs-1625990512670)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20210709205717717.png)]

循环
forof
// 循环键
for (const key of map.keys()) {
            console.log(key);
        }
// 循环值
for (const value of map.values()) {
            console.log(value);
        }
// 循环键值对
for (const [key,value] of map.entries()) {
            console.log([key,value]);
        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E05j36lQ-1625990512672)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20210709210147648.png)]

foreach
 map.forEach((key,value) => {
            console.log(key,value);
        });

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PqQO4xj6-1625990512674)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20210709210333978.png)]

Map类型转换

let map = new Map([['name','lihuina'],['age',18]]);
map => 数组

点语法

console.log([...map]);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRQaSRZc-1625990512676)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20210709210940529.png)]

也可以单独转换键或者值

console.log([...map.keys()]);
console.log([...map.values()]);

在这里插入图片描述

举例:

想把值为lihuina的单独拿出来变成一个新的集合,其他的不变

// 先变为数组,然后过滤器找出想要的
let newArr = [...map].filter(item => {
    return item.includes('lihuina');
});
// 再变回集合
let edu = new Map(newArr);
console.log(...edu.values());   // lihuina

Map类型管理DOM节点

let map = new Map();
       document.querySelectorAll('div').forEach(item=>{
     map.set(item,{
        // 键名是div,内容就是属性值,可以往里面保存任何与DOM节点有关的信息
        content:item.getAttribute('name')
    });
});
console.log(map);

在这里插入图片描述

点击的时候弹出提示消息内容

 // 点击的时候弹出提示消息内容
map.forEach((config,elem)=>{
    // console.log(config);
    // console.log(elem);
    elem.addEventListener("click",()=>{
          alert(config.content);
    });
})
例:使用map类型控制表单提交

点击提交时便会调用post方法,将勾选项中的内容添加到map中,将对象作为键值,键为表单DOM元素,值为错误信息以及是否被选中的状态,Map类型可以方便我们存储这两种类型的数据。

<body>
    <form action="" onsubmit="return post()">
        接受协议:
        <input type="checkbox" name="agreement" error='请接受协议'>
        我是学生:
        <input type="checkbox" name="student" error='网站只对学生开放'>
        <input type="submit">
    </form>
    
    
    <script>
        function post(){
            let map = new Map();
            let inputs = document.querySelectorAll("[error]");
            // console.log(inputs);
            inputs.forEach(item=>{
                map.set(item,{
                   error:item.getAttribute('error'),
                    status:item.checked
                });
            });
            
            // 将map转换为数组,使用every方法,只有全都勾选,状态全为真时才允许提交,否则会弹出错误信息
            // 返回状态信息,有一个不勾选就返回false,就不允许提交
            // 如果只传一个参数elem则会得到一个数组,第一个是元素,第二个是json对象,这样取的话,
            // 如果想获得json对象的话,还得elem[1]这种来取
            // 这里可以使用解构,第二个为config,这样就config直接得到我们想要的数据了
            return [...map].every(([elem,config])=>{
                // 如果状态为真就什么都不做,为假的话就弹出里面的错误消息
                config.status || alert(config.error);
                return config.status;
            })
            // console.log(map);
            // return false;
        }
    </script>
</body>

在这里插入图片描述


WeakMap

WeakMap里面的键只能是对象,像weakset的值必须得是对象

let map = new WeakMap();
// 键为字符串时会报错
// map.set("name","lihuina"); // Invalid value used as weak map key      at WeakMap.set (<anonymous>)
// 键为引用类型(数组,对象等)不会报错
map.set([],"lihuina"); //WeakMap {Array(0) => "lihuina"} 
console.log(map); 

在这里插入图片描述

DOM元素是对象

<body>
    <!-- DOM元素是对象 -->
    <div>lihuina</div>
    <div>baby</div>
    
    <script>
        let divs = document.querySelectorAll('div');
        let map = new WeakMap();
        
        divs.forEach(item=>map.set(item,item.innerHTML));
        console.log(map);
     
    </script>
</body>

在这里插入图片描述
WeakMap的增删改查

// 基本语法
let arr = []; //数组是引用类型
let map = new WeakMap();
// 添加
map.set(arr,'lihuina');
// 删除
map.delete(arr);
// 判断
console.log(map.has(arr));
// values keys size forof 都用不了
console.log(map);
弱类型特性
  let hd = {name:"lihuina"};
  		// 首先让hd和cms变量都指向这个对象
        let cms = hd;
        let map = new WeakMap();
        // 再让map中的键指向这个对象
        map.set(hd,"lihuina.com");
        // 让hd和cms都不指向这个对象了
        hd = null;
        cms = null;
        //这时应该垃圾回收机制已经来了

		// 这时候打印 map时还是会显示出存在的亚子
        console.log(map);
        // 用计时器来看一下吧
        // 浏览器版本不同,有的浏览器用setTimeOut计时器就可以一下子显示出来,我的浏览器需要过时间久一点点才可以,便用这个方法来显示啦,直接看打印结果图就明白啦
        setInterval(function(){
            console.log(map);
        },1000);
        

在这里插入图片描述

  • 清空hd和cms之后map还是会打印出来,刚开始清空的时候,WeakMap还没有感知到

  • 过一段时间之后,系统自检之后会发现这个问题,然后把他修正

  • 因为这个问题的产生,所以WeakMap不让我们使用values keys size forof 这些方法

  • 设置定时器之后,会发现过一段时间就没有了
    在这里插入图片描述

  • 所以利用这个特性,使用WeapMap保存数据的时候,不需要人工清理,只要外面的数据变了,他就会自己消失了

  • 所以WeakMap主要是为了保存受外部影响的数据

例:使用WeakMap开发选课组件

效果图看最后,代码解释就放在注释里面咯
(没有css代码,可以自己设计)
可以自己运行调试一下

<body>
    <div class="ke">
        <ul>
            <li><span> lihuina</span><a href="javascript:;">+</a></li>
            <li><span> baby</span><a href="javascript:;">+</a></li>
            <li><span> lihuina.com</span><a href="javascript:;">+</a></li>
        </ul>
    </div>
    <div class="text">
        <strong id="count">共选了0门课</strong>
        <p id="lists"></p>
    </div>
    <script>
        class Lesson{
            constructor(){
                this.lis = document.querySelectorAll("ul>li");
                // console.log(this.lis);
                this.countElem = document.getElementById('count');
                this.listsElem = document.getElementById('lists');
                // console.log(this.countElem);
                // console.log(this.listsElem);
                this.map = new WeakMap();
            }

            run(){
                this.lis.forEach(li=>{
                    li.querySelector('a').addEventListener('click',event=>{
                        // console.log(li);
                        // console.log(event.target.parentElement);
                        const a = event.target;
                        // console.log(this);
                        const state = li.getAttribute('select');
                        if(state){
                            li.removeAttribute('select');
                            this.map.delete(li);
                            a.innerHTML = "+";
                            a.style.backgroundColor = 'green';
                        }else{
                            this.map.set(li);
                            li.setAttribute('select',true);
                            a.innerHTML = "-";
                            a.style.backgroundColor = 'red';
                        }
                        // console.log(this.map);
                        this.render();
                    }); 
                });
            }

            lists(){
                return [...this.lis].filter(li=>{
                    return this.map.has(li);
                }).map(li=>{
                    return `<span>${li.querySelector('span').innerHTML }</span>`;
                }).join(" ");
            }

            count(){
                return [...this.lis].reduce((count,li)=>{
                    return count += (this.map.has(li)?1:0);
                },0);
            }
            
            render(){
                this.countElem.innerHTML = `共选了${this.count()}门课`;
                this.listsElem.innerHTML = this.lists();
            }
        }
        new Lesson().run();
    </script>
</body>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

文章来源于观看后盾人课程的笔记(自己做的),有问题欢迎纠正

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值