热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ES6新增集合Set和Map

Sets和数组一样,都是一些有序值的的集合,但是Sets和数组又有所不同,首先Sets集合中不能存有相同的值,如果你向Set

  Sets 和数组一样,都是一些有序值的的集合,但是Sets 和数组又有所不同,首先Sets 集合中不能存有相同的值,如果你向Sets 添加重复的值,它会忽略掉, 其次Sets 集合的作用也有所不同,它的主要作用一是存储数据,二是在于看一个值是不是在集合中,而不是对单个值进行操作,Sets 的查找更快。那怎样才能创建一个Sets, 使用new  Set(); 怎样才能添加值呢? 调用add() 方法

let set = new Set();
set.add(1);
set.add(2);set.add({name: 'sam'
})

  刚才我们说了,Sets 集合中不能添加重复的值,如果添加了,Sets 也会把它忽略掉,现在就可以试一试了,添加一个1,

let set = new Set();
set.add(1);
set.add(2);set.add({name: 'sam'
})
set.add(1)

  那我们怎么才能知道有没有添加到set中呢? 它又一个size属性,可以返回集合中又多少个元素, 

console.log(set.size) // 3

  set 中只要3个元素, 表明没有添加成功, 直接console.log(set), 也能看出它里面的包含的值。那这又引出了例外一个问题,Sets 集合是怎么判断两个值是重复或相等呢?内部调用的是Object.is() 方法判断相等性。

  除了调用add() 方法添加数据外,我们也可以创建Sets 的时候,直接进行初始化。new Set() 可接受数组作为参数,如果数组中有重复的值,初始化的时候直接过滤掉。

let set = new Set([1, 1, 2, 3, 3]);
console.log(
set.size) // 3

   添加数据之后,能不能删除呢? 当然可以了,调用 delete() 方法可以删除一个元素,调用clear() 方法直接清空集合。

let set = new Set([1, 1, 2, 3, 3]);
console.log(
set.size) // 3set.delete(1); // 删除集合中的元素1
console.log(set.size); // 2
set.clear(); // 清空集合
console.log(set.size); // 0

  还有一个has 方法,就是判断一个元素是不是在集合中

let set = new Set([1, 1, 2, 3, 3]);
set.has(1); // true
set.has(6); // false

  刚才我们说了,可以使用console.log 来查看集合的内容,其实还有更好的办法,就是forEach 方法,对集合进行迭代。forEach 方法和数组的forEach 用法一致,都是接受一个函数,函数有三个参数,不过这三个参数和数组的不同,因为Sets 集合中并没有index, 对于Sets 集合的迭代来说,第一个是value, 第二个值也是value, 第三个是集合本身,你可能会问,第一个和第二个参数的值一致,为什么还要设置这个参数, 这是因为保持forEach API 的用法一致,如果Sets 的forEach 单独两个参数,那很容易忘掉。

let set = new Set([1, 1, 2, 3, 3]);
set.forEach(function(value, key, ownerSet) {console.log(value, key);console.log(value === key);console.log(ownerSet === set)
})

  既然可以使用数组对Sets集合进行初始化,那么Sets集合能不能转化成数组呢?也可以,使用... 分割符。

let set = new Set([1, 1, 2, 3, 3]);
let arr
= [...set];
console.log(arr);
// [1, 2, 3]

  这时可以发现对数组进行了去重,简单的数组去重,用Sets 集合就可以解决了。

  以上我们创建的set 称为强set(Strong set), 为什么呢? 主要是因为当set 存储对象的时候,它存储的是对象的引用,只要set 存在,它里面引用的对象也会存在,对象就不会被垃圾回收,即使set 外面 这个对象的所有引用都消失了。

let set = new Set();
let obj
= {};set.add(obj);
console.log(
set.size); // 1

  现在set 创建成功了, 并且存储了一个对象的引用obj. 那现在让对象的引用消失,obj =null; 你会发现set 中仍然存在着对象的引用,因为set.size 为1;

obj = null;
console.log(
set.size); // 1

  我们可以把set 转化成数组,看到里面有一个对象

console.log([...set])

  但有时候,我们并不想这么做,尤其是操作dom的时候。如果set 集合中存储的是一个DOM 对象的引用,当我们把这个dom元素删除掉,这个元素的引用 其实就没有作用了,set 中再保留这个 dom 对象的引用也就没有意义了。 简单的dom结构

<div id&#61;"app"><button type&#61;"button" class&#61;"btn">5&#43;6的结果button>div>

  创建set实例&#xff0c;保存这个dom 的引用

let set &#61; new Set();
let btn
&#61; document.getElementsByClassName(&#39;btn&#39;)[0];
set.add(btn);

  然后删除这个btn 元素

document.getElementById(&#39;app&#39;).removeChild(btn);

  这时候&#xff0c;你会发现页面中没有这个元素了&#xff0c;但是btn 和 set 集合中仍然保留这个btn 元素的引用。

console.log(btn);
console.log(set.size); // 1

  btn  好办&#xff0c;直接设置为null 就好了。但是set 中的元素就不好办了&#xff0c;这时ES6 提供了weak set&#xff0c; 专门处理这种引用的问题&#xff0c;如果 set  中引用的对象&#xff0c;就剩下在set 中的引用了&#xff0c;那么set 中的引用就会消失&#xff0c;对象也就可以垃圾回收了。

  创建weak set 使用的weakSet 函数&#xff0c;并且它里面只存对象&#xff0c;add, delete, has 方法和  set 使用一致&#xff0c; 

let weakSet &#61; new WeakSet();
let obj
&#61; {};weakSet.add(obj);
weakSet.has(obj);
weakSet.
delete(obj);

  和set 最大的不同就是我们上面刚说的&#xff0c;如果 obj &#61; null, 就只剩下weakset 中存在对象的引用&#xff0c;那么这个引用也会消失&#xff0c;但是没有更好的判判断方法。

obj &#61; null;

  执行obj &#61; null; 后&#xff0c;我们就可以判断weakSet 中&#xff0c;没有对象的引用了。除了这个不同外&#xff0c; weakset&#xff0c; 不能迭代&#xff0c;没有size 和forEach 方法&#xff0c;它只能存储对象。

  Map

  Map和对象一样&#xff0c;都是键值对的方式存储数据&#xff0c;但是你想&#xff0c;有对象了&#xff0c;还要map 做什么&#xff1f; map 更强大&#xff0c;因为对象的所有key  都是字符串&#xff0c;你即使添加的时候不是字符串&#xff0c;对象也会 key 转化为字符串。

let obj &#61; {};
let num
&#61; 5;
let string
&#61; &#39;5&#39;
obj[num]
&#61; &#39;5 string&#39;;
obj[string]
&#61; &#39;5 number&#39;;
console.log(obj); // {&#39;5&#39; : &#39;5 number&#39;}

    我们给对象添加了两个属性&#xff0c;一个是数字5&#xff0c; 一个是字符串‘5’&#xff0c; 但到最后发现对象中只有一个字符串5. 因为当我们给对象添加数字5的时候&#xff0c;它先转化为字符串‘5’&#xff0c; 发现对象中已经有字符串5 的属性了&#xff0c;就变成了改变对象的属性值了。 map 就不一样了&#xff0c;键和值可以是任意类型。创建map 使用的是new Map, 添加属性使用的是set 方法&#xff0c;set 也简单&#xff0c; 有俩个参数&#xff0c;第一个是key, 第二个是value.

let map &#61; new Map();
map.set(
5, &#39;5 number&#39;);
map.set(
&#39;5&#39;, &#39;5 string&#39;);
console.log(map);
// Map { 5 &#61;> &#39;5 number&#39;, &#39;5&#39; &#61;> &#39;5 string&#39; }

  当我们向map 中增加key/value的时候&#xff0c;它是怎么判断这个key是不是存在map 中呢? 使用的是Object.is() 方法来进行判断&#xff0c;没有进行类型转化&#xff0c;所以 key 可以是任意值了。给map 添加值以后&#xff0c;怎么获取呢&#xff1f;使用get 方法&#xff0c;一个参数key

console.log(map.get(5)); // &#39;5 number&#39;

  除了这两个方法方法外&#xff0c;它还要has, delete, clear 方法&#xff0c;同时有一个 size  属性。 has 接受一个参数key, 判断存不存在&#xff0c;delete 接受一个参数key&#xff0c; 删除这个key&#xff0c; clear 不接受参数&#xff0c;直接清空map. size 以上返回有多少数据。

let map &#61; new Map();
map.set(
5, &#39;5 number&#39;);
map.set(
&#39;5&#39;, &#39;5 string&#39;);console.log(map.has(5)); // true
console.log(map.size); // 2
map.delete(5);
console.log(map.has(
5)); // false
console.log(map.size); // 1
map.clear();
console.log(map.size)
// 0

  Map 也可以使用数组进行初始化&#xff0c;不过&#xff0c;数组要用二维数组&#xff0c;因为map 中的每一项都是key/value,  数组中的每一项也应该有两个值&#xff0c;两个值只能用再用一个数组进行表示了&#xff0c;数组的第一项是key, 第二项是value。

let map &#61; new Map([[&#39;name&#39;, &#39;json&#39;], [&#39;age&#39;, 30]]);

  你可想到key/value 不应该是对象吗&#xff0c;数组中的每一项是对象才对&#xff0c;但我们也说了&#xff0c;对象的key 只能是字符串&#xff0c;所以不能完全表示map&#xff0c;因为map 的key 是任意值&#xff0c;数组正好&#xff0c;数组中的每一项都是任意值&#xff0c;只不过语法比较奇怪&#xff0c; 数组的第一项是key&#xff0c; 第二项是value.

  获取到map 后&#xff0c;可以使用forEach 进行迭代&#xff0c;用法也会数组一致。

let map &#61; new Map([[&#39;name&#39;, &#39;json&#39;], [&#39;age&#39;, 30]]);
map.forEach((value, key, ownerMap)
&#61;> {console.log(value, key);console.log(map &#61;&#61;&#61; ownerMap)
})

  和WeakSet 一样&#xff0c;map 也提供了WeakMap&#xff0c; WeakMap 的key 是必须是对象&#xff0c;如果 key引用的一个对象&#xff0c;只剩下在weakMap的key 中引用&#xff0c;其他的对这个对象的引用都不存在了&#xff0c;weakMap 中的key以及它对应的value就会自动删除。weak map 的创建是new WeakMap(); 它有set get, has, delete 方法&#xff0c;但没有size, clear(), forEach  等。

let map &#61; new Map();
let btn
&#61; document.getElementsByClassName(&#39;btn&#39;)[0];map.set(btn, &#39;btn&#39;);
map.get(btn);
map.has(btn);
map.
delete(btn);btn &#61; null; // map 中的key btn 以及它的value 会自动删除

  weak map  还要一个作用&#xff0c;可以创造对象的私有属性&#xff0c; 当我创建对象的时候&#xff0c;通常写一个构造函数

function Person(name) {this. name &#61; name;
}Person.prototype.getName
&#61; function() {return this.name;
}

  但这时&#xff0c;创建一个Person 对象的时候&#xff0c;我们可以直接访问name 属性&#xff0c;

const person &#61; new Person(&#39;sam&#39;);
console.log(person.name)
// sam

  但是我们不想让用户直接访问name 属性&#xff0c; 直接使用下面的方法

let Person &#61; (function(){let privateData &#61; new WeakMap();function Person(name) {privateData.set(this, {name: name})}Person.prototype.getName &#61; function() {return privateData.get(this).name;}return Person;
})()let person
&#61; new Person(&#39;json&#39;);
console.log(person.getName())
// josn

 

转:https://www.cnblogs.com/SamWeb/p/10872901.html



推荐阅读
author-avatar
垚垚8858
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有