【读书笔记】【深入理解ES6】#7-Set集合和Map集合
ES6新标准中将Set集合和Map集合添加到JS中。
ES5中Set集合和Map集合
在ES5中,开发者们用对象属性来模拟这两种集合。
var set = Object.create(null);
set.foo = true;
// 检查属性是否存在
if (set.foo) {
// ...
}
模拟Map集合同上例类似。
如果只是简单的应用上面的方法基本上能满足需求,但是如果碰到对象属性名的限制,就会产生一些问题。
var map = Object.create(null);
map[5] = "foo";
console.log(map["5"]); // "foo"
console.log(map); // {5: "foo"}
虽然map中存储的属性键名是数值型的5,但 map["5"] 引用的是同一个属性。
用对象作为键名也有类似的问题。
var map = Object.create(null),
key1 = {},
key2 = {};
map[key1] = "foo";
console.log(map[key2]); // "foo"
console.log(map); // {[object Object]: "foo"}
上例中 map[key1] 和 map[key2] 也引用了同一个值。因为 key1 和 key2 会被转换为对象的默认字符串 "[object Object]"。
ES6中的Set集合
ES6中新增的Set集合是一种有序列表,其中还有一些相互独立的非重复值,通过Set集合可以快速访问其中的数据,更有效地追踪各种离散值。
创建Set集合并添加元素
let set = new Set();
set.add(5);
set.add("5");
console.log(set.size); // 2
console.log(set); // Set(2) {5, "5"}
向Set集合中添加对象
let set = new Set(),
key1 = {},
key2 = {};
set.add(key1);
set.add(key2);
console.log(set.size); // 2
console.log(set); // Set(2) {{…}, {…}}
如果多次传入相同的值,后面的调用实际上会被忽略。
let set = new Set();
set.add(5);
set.add("5");
set.add(5); // 重复 - 本次调用直接被忽略
console.log(set.size); // 2
console.log(set); // Set(2) {5, "5"}
使用数组来初始化Set集合,并且同时可以出去重复的元素。
let set = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
console.log(set.size); // 5
console.log(set); // Set(5) {1, 2, 3, 4, 5}
Note
实际上,Set构造函数可以接受所有可迭代对象作为参数,数组、Set集合、Map集合都是可迭代的,因而都可以作为Set构造函数的参数使用;构造函数通过迭代器从参数中提取值。
通过 has() 方法可以检测Set集合中是否存在某个值
let set = new Set();
set.add(5);
set.add("5");
console.log(set.has(5)); // true
console.log(set.has(6)); // false
移除元素
delete() 方法可以移除Set集合中的某一个元素;
clear() 方法可以移除集合中所有元素。
let set = new Set();
set.add(5);
set.add("5");
console.log(set.has(5)); // true
console.log(set.size); // 2
set.delete(5);
console.log(set.has(5)); // false
console.log(set.size); // 1
set.clear();
console.log(set.has("5")); // false
console.log(set.size); // 0
Set集合的forEach()方法
forEach() 方法的回调函数接受以下3个参数:
- Set集合中下一次索引的位置
- 与第一个参数一样的值
- 被遍历的Set集合本身
需要注意的是这里的第一和第二个参数是一样的。这是为了和数组和Map集合的forEach()方法统一。
let set = new Set([1, 2]);
set.forEach(function(value, key, ownerSet) {
console.log(key + " " + value);
console.log(ownerSet === set);
});
// 输出结果:
// 1 1
// 5 true
// 4 2 2
// 5 true
如果需要在回调函数中使用this引用,则要将this作为第二个参数传入forEach()函数。
let set = new Set([1, 2]);
let processor = {
output(value) {
console.log(value);
},
process(dataSet) {
dataSet.forEach(function(value) {
this.output(value);
}, this);
}
};
processor.process(set);
这里可以使用箭头函数,这样就可以不用再将this传入forEach()方法了。
let set = new Set([1, 2]);
let processor = {
output(value) {
console.log(value);
},
process(dataSet) {
dataSet.forEach(value => this.output(value));
}
};
processor.process(set);
将Set集合转换为数组
let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array); // [1, 2, 3, 4, 5]
使用Set集合实现数组的去重
function eliminateDuplicates(items) {
return [...new Set(items)];
}
let numbers = [1, 2, 3, 3, 3, 4, 5],
noDuplicates = eliminateDuplicates(numbers);
console.log(noDuplicates);
Weak Set 集合
弱引用的Set集合。用法同Set集合基本一样。
let set = new WeakSet(),
key = {};
// 向集合中添加对象
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false
两种Set类型的主要区别
Weak Set保存的是对象值得弱引用。
当Weak Set中的某个对象的所有强引用都被移除的时候,该对象也会自动从Weak Set中移除。
let set = new WeakSet(),
key = {};
// 向集合中添加对象
set.add(key);
console.log(set.has(key)); // true
// 移除对象key的最后一个强引用(Weak Set中的引用也会自动移除)
key = null;
Weak Set 集合和普通 Set 集合的差别
- 在WeakSet的实例中,如果向 add()、has()和delete()这3个方法传入非对象参数都会导致程序报错;
- Weak Set 集合不可迭代,所以不能被用于 for-of 循环;
- Weak Set 集合不暴露任何迭代器(例如 keys() 和 values() 方法),所以无法通过程序本身来检测其中的内容;
- Weak Set 集合不支持 forEach() 方法;
- Weak Set 集合不支持 size 属性。
Weak Set 集合的功能看似受限,其实这是为了让它能够正确的处理内存中数据。
总之,如果你只需要跟踪对象引用,你更应该使用 Weak Set 集合而不是 Set 集合。
ES6中的 Map 集合
ES6中的 Map 类型是一种储存着许多键值对的有序列表,其中键名和对应的值支持所有的数据类型。
键名的等价判断是通过 Object.is() 方法实现的。
let map = new Map();
map.set("site", "liujiajia.me");
map.set("year", 2017);
console.log(map.get("site")); // "liujiajia.me"
console.log(map.get("year")); // 2017
使用对象作为键名
let map = new Map,
key1 = {},
key2 = {};
map.set(key1, 9);
map.set(key2, 32);
console.log(map.get(key1)); // 9
console.log(map.get(key2)); // 32
Map集合支持的方法
Map集合和Set集合有如下3个通用方法:
- has(key)
检测指定的键名在Map集合中是否存在 - delete(key)
从Map集合中移除指定键名及其对应的值 - clear()
移除Map集合中所有的键值对
let map = new Map();
map.set("name", "JiaJia");
map.set("age", 32);
console.log(map.has("name")); // true
console.log(map.get("name")); // "JiaJia"
console.log(map.has("age")); // true
console.log(map.get("age")); // 32
console.log(map.size); // 2
map.delete("name");
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.size); // 1
map.clear();
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.has("age")); // false
console.log(map.get("age")); // undefined
console.log(map.size); // 0
Map集合的初始化方法
可以传入一个数组来初始化Map集合。
数组中的每一个元素都是一个子数组,子数组中包含一个键值对的键名和值两个元素。
let map = new Map([["name", "JiaJia"], ["age", 32]]);
console.log(map.has("name")); // true
console.log(map.get("name")); // "JiaJia"
console.log(map.has("age")); // true
console.log(map.get("age")); // 32
console.log(map.size); // 2
Map集合的forEach()方法
和数组的forEach()方法类似,回调函数都接受3个参数:
- Map集合中下一次索引的位置
- 值对应的键名
- Map集合本身
let map = new Map([["name", "JiaJia"], ["age", 32]]);
map.forEach(function(value, key, ownerMap) {
console.log(key + " " + value);
console.log(ownerMap === map);
});
// 执行结果:
// name JiaJia
// true
// age 32
// true
同Set集合一样,可以指定forEach()方法的第二个参数作为回调函数的this值。
Weak Map 集合
Weak Map 是弱引用的 Map 集合,也用于存储对象的弱引用。
- Weak Map 集合中的键名必须是对象;
- 只有键名保存的是弱引用,键名对应的值如果是个对象,则保存的是该对象的强引用。
Weak Map 最大的用途是保存Web页面中的DOM元素。
let map = new WeakMap(),
element = document.querySelector(".element");
map.set(element, "Original");
let value = map.get(element);
console.log(value); // "Original"
// 移除element元素
element.parentNode.removeChild(element);
element = null;
// 此时 Weak Map 集合为空
私有对象数据
Weak Map 还可以用于存储对象实例的私有数据。
在ES6中所有属性都是公开的。如果想存储一些只对对象开放的数据,则需要一些创造力。
下例使用约定作为私有属性:
function Person(name) {
this._name = name;
}
Person.prototype.getName = function() {
return this._name;
};
看似是只允许通过 getName() 方法获取name属性,但其实仍然可以通过给实例的 _name 属性赋值来更改该属性值。
let user = new Person("JiaJia")
console.log(user.getName()); // "JiaJia"
user._name = "Dlph";
console.log(user.getName()); // "Dlph"
在ES5中,可以通过下面这种模式创建一个对象接近真正的私有数据。
var Person = (function() {
var privateData = {},
privateId = 0;
function Person(name) {
Object.defineProperty(this, "_id", { value: privateId++ });
privateData[this._id] = {
name: name
};
}
Person.prototype.getName = function() {
return privateData[this._id].name;
}
return Person;
}());
let user1 = new Person("JiaJia");
console.log(user1); // Person {_id: 0}
console.log(user1.getName()); // "JiaJia"
var user2 = new Person("Dlph");
console.log(user2); // Person {_id: 1}
console.log(user2.getName()); // "Dlph"
上例中的 privateData 和 privateId 变量被隐藏了起来,在外面无法查看及更改。
该方法最大的问题是,如果不主动管理,由于无法获知对象实例何时被销毁,因此 privateData 中的数据就永远不会消失。而使用 Weak Map 集合就可以解决该问题。
let Person = (function() {
let privateData = new WeakMap();
function Person(name) {
privateData.set(this, { name });
}
Person.prototype.getName = function() {
return privateData.get(this).name;
}
return Person;
}());
let user1 = new Person("JiaJia");
console.log(user1); // Person {}
console.log(user1.getName()); // "JiaJia"
let user2 = new Person("Dlph");
console.log(user2); // Person {}
console.log(user2.getName()); // "Dlph"
user1 = null;
user2 = null;
使用 Weak Map 来存储私有数据,只要对象实例被销毁,相关信息也会被销毁,从而保证了信息的私有性。
Weak Map 集合的使用方式及使用限制
当要在 Weak Map 和 普通 Map 集合之间进行选择时,如果只用对象作为集合的键名,那么 Weak Map 是最好的选择。
相对于 Map 集合而言, Weak Map 集合对用户的可见度更低,其不支持通过 forEach()方法、size属性及clear()方法来管理集合中的元素。
如果只想使用非对象名作为键名,那么普通的Map集合是唯一的选择。
【读书笔记】【深入理解ES6】#7-Set集合和Map集合的更多相关文章
- Java集合的实现细节—Set集合和Map集合
Set:代表无序.不可重复的集合 Map:代表key-value对集合,也称为关联数组 从表面上看,Set和Map相似性很少,但实际上可以说Map集合时Set集合的扩展. 1.Set集合和Map集合的 ...
- 【spring set注入 注入集合】 使用set注入的方式注入List集合和Map集合/将一个bean注入另一个Bean
Dao层代码: package com.it.dao; public interface SayHell { public void sayHello(); } Dao的Impl实现层: packag ...
- Java List集合和Map集合的综合应用
public static void main(String[] args) { //--------------------------------------------------------- ...
- 编写Java程序,使用List集合和Map集合输出 市和区
如图: 代码: import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java ...
- Scala集合和Java集合对应转换关系
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 用Scala编码的时候,经常会遇到scala集合和Java集合互相转换的case,特意mark一 ...
- ES6中的Set和Map集合
前面的话 在ES6标准制定以前,由于可选的集合类型有限,数组使用的又是数值型索引,因而经常被用于创建队列和栈.如果需要使用非数值型索引,就会用非数组对象创建所需的数据结构,而这就是Set集合与Map集 ...
- java基础33 Set集合下的HashSet集合和TreeSet集合
单例集合体系: ---------| collection 单例集合的根接口--------------| List 如果实现了list接口的集合类,具备的特点:有序,可重复 注:集合 ...
- 20150206读书笔记<深入理解计算机系统>
●第一章 C是系统级编程的首选.C++显示支持抽象,属于应用级程序设计语言. 简单例子: 一个典型系统的硬件组成: 存储器的层次结构: 注:存储器层次结构的设计思想是,该层存储器作为下一层存储器的高速 ...
- python 进阶读书笔记1 -- 理解python一切皆对象
理解python一切皆对象: 1.所有的类都是由type创建的 2.所有的类的基类都是object 3.type是类,也是实例,type的基类是object,type对象是由type创建的 4.obj ...
随机推荐
- Vboxmanage改动uuid报错的解决的方法
我的环境: Virtualbox 4.3.10 r93012 操作系统:win7 问题:Virtualbox在使用拷贝的虚拟盘时会提示uuid冲突: Because a hard disk with ...
- HDU1598 find the most comfortable road 【并查集】+【枚举】
find the most comfortable road Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- Order笔记-数据库创建
过程: 1,为这个项目新建一个用户名(实例),专门用于这个项目 2,建表 问题: 列在此处不允许: 笔记: 建表设置默认值: alter table 表名 modify 字段名 default 默认值 ...
- 对于是否在一个python程序中编写函数的启发
那我们到底是应该直接使用这些模块级别的函数呢,还是先编译一个模式对象,再调用模式对象的方法呢?这其实取决于正则表达式的使用频率,如果说我们这个程序只是偶尔使用到正则表达式,那么全局函数是比较方便的:如 ...
- ABP入门系列(21)——切换MySQL数据库
ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 Abp支持MySql已经不是什么新鲜事了,但按照官方文档:Entity Framewo ...
- Grafana4.2安装
一.文件准备 1.1 文件名称 grafana-4.2.0-1.x86_64.rpm 1.2 下载地址 https://grafana.com/grafana/download 二.工具准备 2.1 ...
- JavaScript定时器:setTimeout()和setInterval()
1 超时调用setTimeout() 顾名思义,超时调用的意思就是在一段实际之后调用(在执行代码之前要等待多少毫秒) setTimeout()他可以接收两个参数: 1 要执行的代码或函数 2 毫秒(在 ...
- 网友"就像一支烟"山寨币分析估值方法
[注:素材取自QQ群,2017年12月28日的聊天记录."就像一支烟"分享了自己的山寨币分析估值方法.因为删去了其他人的聊天记录,部分文字可能断章取义,仅供参考,具体情况请自行分析 ...
- VR、AR、MR定义区别
近日, 获得谷歌5亿美元融资的技术公司Magic Leap在WSJD展会中放出了一段实录视频,引起不小骚动.如今,也有媒体称他们为MR公司,那么VR.AR.MR之间到底有什么区别呢. VR.AR.MR ...
- ArcGIS API for JavaScript 与 Vue.js
我一开始学Vue.js的时候还仅限于script标签里引用vue.js文件这种纯前端静态的做法,我也不知道vue.js究竟是怎么生成页面的. 我习惯性地把AJS的js文件也用script标签引用进来, ...