es6学习笔记8--Map数据结构
Map
Map结构的目的和基本用法
JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是只能用字符串当作键。这给它的使用带来了很大的限制。
var data = {}; var element = document.getElementById("myDiv");data[element] = metadata; data["[Object HTMLDivElement]"] // metadata
上面代码原意是将一个DOM节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[Object HTMLDivElement]
。
为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
var m = new Map(); var o = {p: "Hello World"};m.set(o, "content") m.get(o) // "content" m.has(o) // true m.delete(o) // true m.has(o) // false
上面代码使用set方法,将对象o当作m的一个键,然后又使用get方法读取这个键,接着使用delete方法删除了这个键。
作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
var map = new Map([["name", "张三"], ["title", "Author"]]);map.size // 2 map.has("name") // true map.get("name") // "张三" map.has("title") // true map.get("title") // "Author"
上面代码在新建Map实例时,就指定了两个键name
和title
。
注意,只有对同一个对象的引用,Map结构才将其视为同一个键。这一点要非常小心。
var map = new Map();map.set(['a'], 555); map.get(['a']) // undefined
上面代码的set
和get
方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get
方法无法读取该键,返回undefined
。
同理,同样的值的两个实例,在Map结构中被视为两个键。
var map = new Map();var k1 = ['a']; var k2 = ['a'];map .set(k1, 111) .set(k2, 222);map.get(k1) // 111 map.get(k2) // 222
上面代码中,变量k1
和k2
的值是一样的,但是它们在Map结构中被视为两个键。
由上可知,Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
如果Map的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map将其视为一个键,包括0和-0。另外,虽然NaN不严格相等于自身,但Map将其视为同一个键。
let map = new Map();map.set(NaN, 123); map.get(NaN) // 123 map.set(-0, 123); map.get(+0) // 123
实例的属性和操作方法
Map结构的实例有以下属性和操作方法。
(1)size属性
size
属性返回Map结构的成员总数。
(2)set(key, value)
set
方法设置key
所对应的键值,然后返回整个Map结构。如果key
已经有值,则键值会被更新,否则就新生成该键。
(3)get(key)
get
方法读取key
对应的键值,如果找不到key
,返回undefined
。
(4)has(key)
has
方法返回一个布尔值,表示某个键是否在Map数据结构中。
(5)delete(key)
delete
方法删除某个键,返回true。如果删除失败,返回false。
(6)clear()
clear
方法清除所有成员,没有返回值。
遍历方法
Map原生提供三个遍历器生成函数和一个遍历方法。
- keys():返回键名的遍历器。
- values():返回键值的遍历器。
- entries():返回所有成员的遍历器。
- forEach():遍历Map的所有成员。
// 等同于使用map.entries() for (let [key, value] of map) {console.log(key, value); }
上面的那个例子,表示Map结构的默认遍历器接口(Symbol.iterator
属性),就是entries
方法。
map[Symbol.iterator] === map.entries // true
Map结构转为数组结构,比较快速的方法是结合使用扩展运算符(...)。
WeakMap
WeakMap
结构与Map
结构基本类似,唯一的区别是它只接受对象作为键名(null
除外),不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。
var map = new WeakMap() map.set(1, 2) // TypeError: 1 is not an object! map.set(Symbol(), 2) // TypeError: Invalid value used as weak map key
上面代码中,如果将1
和Symbol
作为WeakMap的键名,都会报错。
WeakMap
的设计目的在于,键名是对象的弱引用(垃圾回收机制不将该引用考虑在内),所以其所对应的对象可能会被自动回收。当对象被回收后,WeakMap
自动移除对应的键值对。典型应用是,一个对应DOM元素的WeakMap
结构,当某个DOM元素被清除,其所对应的WeakMap
记录就会自动被移除。基本上,WeakMap
的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap
结构有助于防止内存泄漏。
下面是WeakMap
结构的一个例子,可以看到用法上与Map
几乎一样。
var wm = new WeakMap(); var element = document.querySelector(".element");wm.set(element, "Original"); wm.get(element) // "Original" element.parentNode.removeChild(element); element = null; wm.get(element) // undefined
上面代码中,变量wm
是一个WeakMap
实例,我们将一个DOM
节点element
作为键名,然后销毁这个节点,element
对应的键就自动消失了,再引用这个键名就返回undefined
。
WeakMap与Map在API上的区别主要是两个,一是没有遍历操作(即没有key()
、values()
和entries()
方法),也没有size
属性;二是无法清空,即不支持clear
方法。这与WeakMap
的键不被计入引用、被垃圾回收机制忽略有关。因此,WeakMap
只有四个方法可用:get()
、set()
、has()
、delete()
。
WeakMap的另一个用处是部署私有属性。
let _counter = new WeakMap(); let _action = new WeakMap();class Countdown {constructor(counter, action) {_counter.set(this, counter);_action.set(this, action);}dec() {let counter = _counter.get(this);if (counter < 1) return;counter--;_counter.set(this, counter);if (counter === 0) {_action.get(this)();}} }let c = new Countdown(2, () => console.log('DONE'));c.dec() c.dec() // DONE
上面代码中,Countdown类的两个内部属性_counter
和_action
,是实例的弱引用,所以如果删除实例,它们也就随之消失,不会造成内存泄漏。
转载于:https://www.cnblogs.com/huansky/p/5680573.html
es6学习笔记8--Map数据结构相关推荐
- ES6学习笔记04:Set与Map
ES6学习笔记04:Set与Map JS原有两种数据结构:Array与Object,ES6新增两种数据结构:Set与Map 一.Set数据结构 Set类似于数组,但是成员值不允许重复,因此主要用于数据 ...
- ES6学习笔记(五):轻松了解ES6的内置扩展对象
前面分享了四篇有关ES6相关的技术,如想了解更多,可以查看以下连接 <ES6学习笔记(一):轻松搞懂面向对象编程.类和对象> <ES6学习笔记(二):教你玩转类的继承和类的对象> ...
- # es6 学习笔记
es6 学习笔记 let变量 let和var用法级别一样 let不能重复声明,但是var可以 var varIns = "A"; var varIns = "B" ...
- es6学习笔记-字符串的扩展_v1.0_byKL
es6学习笔记-字符串的扩展_v1.0 字符的Unicode表示法 JavaScript 允许使用uxxxx的形式表示一个字符,但在 ES6 之前,单个码点仅支持u0000到uFFFF,超出该范围的必 ...
- ES6学习笔记03:变量的解构赋值
ES6学习笔记03:变量的解构赋值 如果想从复杂数据结构(数组.对象)中获取某一个数据,可能需要大量的遍历操作才能完成.通过解构赋值,这一过程可以得到简化. 1.字符串的解构赋值 其实,Python也 ...
- ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能
前两篇文章主要介绍了类和对象.类的继承,如果想了解更多理论请查阅<ES6学习笔记(一):轻松搞懂面向对象编程.类和对象>.<ES6学习笔记(二):教你玩转类的继承和类的对象>, ...
- ES6学习笔记02:let 与 const
ES6学习笔记02:let 与 const 用var声明的变量会造成全局污染,于是就产生了新的声明方式. 1.let 用let声明变量,必须先声明后使用. 在for循环头里用let定义循环变量i,那么 ...
- ES6学习笔记01:Symbol数据类型
ES6学习笔记01:Symbol数据类型 1.Symbol定义 浏览demo01.html: 2.Symbol作对象属性名 Symbol函数可以接收一个字符串作为参数,表示对Symbol实例的描述,输 ...
- es6学习笔记-顶层对象_v1.0_byKL
es6学习笔记-顶层对象_v1.0 (虽然是笔记,但是基本是抄了一次ruan大师的文章了) 顶层对象 顶层对象,在浏览器环境指的是window对象,在Node指的是global对象. ES5之中,顶层 ...
- ES6学习笔记二arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
最新文章
- WEB程序代码优化入手的几方面
- LINQ学习笔记之四:查询内存对象
- 跟前腾讯总监学Java实战项目
- 【AGC005F】Many Easy Problems (NTT)
- C语言读取load格式文件,求指导,如何用c语言实现读取*.raw格式图像
- 谷歌秋季新品发布会即将召开 Pixel 4系列将正式亮相
- 汽车和山羊问题matlab_三门问题:为什么换门会增加得到汽车的概率
- nodejs基础 -- 全局对象
- 常见字符编码详解ANSI,UTF-8,UCS,GBK,GB2312,BIG5
- 2022年深圳杯建模A题思路: 破除“尖叫效应”与“回声室效应”,走出“信息茧房”
- 图片怎么转换成文字?几个好用的方法快来查阅
- python +selenium 实现教学质量评价自动化
- 牛逼,我用Python做了一个word、PPT水印添加器!还带加密功能!
- apache整合tomcat实现web服务器的动静态资源的分离解析
- .pfx格式和.Cer格式的区别
- 生信步骤|转录组测序上游分析:hisat2+samtools+stringtie
- Flink的State概述
- 如何高效管理电脑里的文件
- 高手路过--菜鸟版系统安装==(图文安装教程)+(最新win7+win8系统)+系统工具
- NGUI图集分解 切割
热门文章
- 远程控制virtual box虚拟机系统的三种方式
- 遮罩,在指定元素上进行遮罩
- 学生上课睡觉班主任怎么处理_学生上课睡觉,老师的管与不管,不是你看到的那么简单...
- 非本地类型不能定义方法 cannot define new methods on non-local type time.Duration
- 难忘的一天——装操作系统(三)
- PyTorch代码调试利器_TorchSnooper
- LeetCode简单题之词典中最长的单词
- 合肥工业大学—SQL Server数据库实验一:数据库的创建和删除
- TVM代码生成codegen
- 旷视MegEngine核心技术升级