)
既然可以使用数组对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="app">
<button type="button" class="btn">5+6的结果</button>
</div>
创建set实例,保存这个dom 的引用
let set = new Set();
let btn = document.getElementsByClassName('btn')[0];
set.add(btn);
然后删除这个btn 元素
document.getElementById('app').removeChild(btn);
这时候,你会发现页面中没有这个元素了,但是btn 和 set 集合中仍然保留这个btn 元素的引用。
console.log(btn);
console.log(set.size); // 1
btn 好办,直接设置为null 就好了。但是set 中的元素就不好办了,这时ES6 提供了weak set, 专门处理这种引用的问题,如果 set 中引用的对象,就剩下在set 中的引用了,那么set 中的引用就会消失,对象也就可以垃圾回收了。
创建weak set 使用的weakSet 函数,并且它里面只存对象,add, delete, has 方法和 set 使用一致,
let weakSet = new WeakSet();
let obj = {};
weakSet.add(obj);
weakSet.has(obj);
weakSet.delete(obj);
和set 最大的不同就是我们上面刚说的,如果 obj = null, 就只剩下weakset 中存在对象的引用,那么这个引用也会消失,但是没有更好的判判断方法。
obj = null;
执行obj = null; 后,我们就可以判断weakSet 中,没有对象的引用了。除了这个不同外, weakset, 不能迭代,没有size 和forEach 方法,它只能存储对象。
Map和对象一样,都是键值对的方式存储数据,但是你想,有对象了,还要map 做什么? map 更强大,因为对象的所有key 都是字符串,你即使添加的时候不是字符串,对象也会 key 转化为字符串。
let obj = {};
let num = 5;
let string = '5'
obj[num] = '5 string';
obj[string] = '5 number';
console.log(obj); // {'5' : '5 number'}
我们给对象添加了两个属性,一个是数字5, 一个是字符串‘5’, 但到最后发现对象中只有一个字符串5. 因为当我们给对象添加数字5的时候,它先转化为字符串‘5’, 发现对象中已经有字符串5 的属性了,就变成了改变对象的属性值了。 map 就不一样了,键和值可以是任意类型。创建map 使用的是new Map, 添加属性使用的是set 方法,set 也简单, 有俩个参数,第一个是key, 第二个是value.
let map = new Map();
map.set(5, '5 number');
map.set('5', '5 string');
console.log(map); // Map { 5 => '5 number', '5' => '5 string' }
当我们向map 中增加key/value的时候,它是怎么判断这个key是不是存在map 中呢? 使用的是Object.is() 方法来进行判断,没有进行类型转化,所以 key 可以是任意值了。给map 添加值以后,怎么获取呢?使用get 方法,一个参数key
console.log(map.get(5)); // '5 number'
除了这两个方法方法外,它还要has, delete, clear 方法,同时有一个 size 属性。 has 接受一个参数key, 判断存不存在,delete 接受一个参数key, 删除这个key, clear 不接受参数,直接清空map. size 以上返回有多少数据。
let map = new Map();
map.set(5, '5 number');
map.set('5', '5 string');
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 也可以使用数组进行初始化,不过,数组要用二维数组,因为map 中的每一项都是key/value, 数组中的每一项也应该有两个值,两个值只能用再用一个数组进行表示了,数组的第一项是key, 第二项是value。
let map = new Map([['name', 'json'], ['age', 30]]);
你可想到key/value 不应该是对象吗,数组中的每一项是对象才对,但我们也说了,对象的key 只能是字符串,所以不能完全表示map,因为map 的key 是任意值,数组正好,数组中的每一项都是任意值,只不过语法比较奇怪, 数组的第一项是key, 第二项是value.
获取到map 后,可以使用forEach 进行迭代,用法也会数组一致。
let map = new Map([['name', 'json'], ['age', 30]]);
map.forEach((value, key, ownerMap) => {
console.log(value, key);
console.log(map === ownerMap)
和WeakSet 一样,map 也提供了WeakMap, WeakMap 的key 是必须是对象,如果 key引用的一个对象,只剩下在weakMap的key 中引用,其他的对这个对象的引用都不存在了,weakMap 中的key以及它对应的value就会自动删除。weak map 的创建是new WeakMap(); 它有set get, has, delete 方法,但没有size, clear(), forEach 等。
let map = new Map();
let btn = document.getElementsByClassName('btn')[0];
map.set(btn, 'btn');
map.get(btn);
map.has(btn);
map.delete(btn);
btn = null; // map 中的key btn 以及它的value 会自动删除
weak map 还要一个作用,可以创造对象的私有属性, 当我创建对象的时候,通常写一个构造函数
function Person(name) {
this. name = name;
Person.prototype.getName = function() {
return this.name;
但这时,创建一个Person 对象的时候,我们可以直接访问name 属性,
const person = new Person('sam');
console.log(person.name) // sam
但是我们不想让用户直接访问name 属性, 直接使用下面的方法
let Person = (function(){
let privateData = new WeakMap();
function Person(name) {
privateData.set(this, {name: name})
Person.prototype.getName = function() {
return privateData.get(this).name;
return Person;
let person = new Person('json');
console.log(person.getName()) // josn