Map
Map 是有序无重复的数据结构,“键” 的范围不限于字符串,各种类型的值 (包括对象) 都可以当作键,键是根据添加的顺序决定的;初始化 Map 对象时,如果默认参数的数组中超过两个以上的值不会被 Map 对象读取;
Map 也实现了 iterator 接口,所以可使用 「扩展运算符」 和 「for…of…」 进行遍历;
Map 属性和方法
方法名 | 描述 |
---|---|
size | 属性,返回 Map 实例的长度 |
set() | 接收键值对,向 Map 实例中添加元素 |
get() | 传入指定的 key 获取 Map 实例上的值 |
has() | 传入指定的 key 查找在 Map 实例中是否存在 |
delete() | 传入指定的 key 删除 Map 实例中对应的值 |
clear() | 清空 Map 实例 |
values() | 得到 Map 实例中的值作为一个可以遍历的对象,可以使用 .next().value 取值 |
keys() | 得到 Map 实例中的键作为一个可以遍历的对象,可以使用 .next().value 取值 |
entries() | 得到 Map 实例中的键值作为一个可以遍历的对象,可以使用 .next().value 取值 |
基本使用
// 创建一个非空 map
let m2 = new Map([
['name', 'ws'],
['slogon', '…']
]);
// 获取 m2
console.log(m2); // {"name" => "ws", "slogon" => "…"}
// 使用扩展运算符
console.log([...m2]); // [["name", "ws"], ["slogon", "…"]]
// 获取映射元素的个数
console.log(m2.size); // 2
// 添加映射值
console.log(m2.set('age', 6));
//获取映射值
console.log(m2.get('age')); // 6
//检测是否有该映射
console.log(m2.has('age')); // true
//清除
console.log(m2.clear());
var map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
var values = map.values()
console.log(values.next().value); // 1
console.log(values.next().value); // 2
console.log(values.next().value); // 3
var map = new Map([["x", 1], ["y", 2], ["z", 3]]);
map.keys(); // MapIterator {'x', 'y', 'z'}
map.values(); // MapIterator {1, 2, 3}
map.entries(); // MapIterator {'x' => 1, 'y' => 2, 'z' => 3}
for(var [key, value] of map.entries()) {
console.log(key, value);
}
// x, 1
// y, 2
// z, 3
Map VS Object
Map 和 Object 有非常多的相似的地方,Map 的出现也是为了弥补 Object 的不足;
Object 的键只能是字符串,Map 的键可以是任意类型的值 (包括对象),所以 Map 是一种更完善的 Hash 结构实现;
判断键值相等的问题
NaN 是与 NaN 相等的 (虽然 NaN !== NaN),剩下所有其它的值是根据 === 运算符的结果判断是否相等;
在目前的 ECMAScript 规范中,-0 和 +0 被认为是相等的,尽管这在早期的草案中并不是这样;
手写 map
class MyMap {
constructor(iterable = []) {
// 验证是否是可迭代的对象
if (typeof iterable[Symbol.iterator] !== "function") {
throw new TypeError(`你提供的${iterable}不是一个可迭代的对象`);
}
this._datas = [];
for (const item of iterable) {
// item 也得是一个可迭代对象
if (typeof item[Symbol.iterator] !== "function") {
throw new TypeError(`你提供的${item}不是一个可迭代的对象`);
}
const iterator = item[Symbol.iterator]();
const key = iterator.next().value;
const value = iterator.next().value;
this.set(key, value);
}
}
set(key, value) {
const obj = this._getObj(key);
if (obj) {
//修改
obj.value = value;
} else {
this._datas.push({
key,
value,
});
}
}
get(key) {
const item = this._getObj(key);
if (item) {
return item.value;
}
return undefined;
}
get size() {
return this._datas.length;
}
delete(key) {
for (let i = 0; i < this._datas.length; i++) {
const element = this._datas[i];
if (this.isEqual(element.key, key)) {
this._datas.splice(i, 1);
return true;
}
}
return false;
}
clear() {
this._datas.length = 0;
}
/**
* 根据key值从内部数组中,找到对应的数组项
* @param {*} key
*/
_getObj(key) {
for (const item of this._datas) {
if (this.isEqual(item.key, key)) {
return item;
}
}
}
has(key) {
return this._getObj(key) !== undefined;
}
/**
* 判断两个数据是否相等
* @param {*} data1
* @param {*} data2
*/
isEqual(data1, data2) {
if (data1 === 0 && data2 === 0) {
return true;
}
return Object.is(data1, data2);
}
*[Symbol.iterator]() {
for (const item of this._datas) {
yield [item.key, item.value];
}
}
forEach(callback) {
for (const item of this._datas) {
callback(item.value, item.key, this);
}
}
}
WeakMap
WeakMap 的 key 只能是对象,值可以是任意类型的,和 WeakSet 一样 WeakMap 对 key 的引用是弱引用,如果没有其他对象引用,GC 会对该对象进行回收;
WeakMap 的 key 是基本类型数据时就会报错;
方法
方法名 | 描述 |
---|---|
set() | 接收键值对,向 WeakMap 实例中添加元素 |
get() | 传入指定的 key 获取 WeakMap 实例上的值 |
has() | 传入指定的 key 查找在 WeakMap 实例中是否存在 |
delete() | 传入指定的 key 删除 WeakMap 实例中对应的值 |
示例
// 示例 1
var wm1 = new WeakMap();
var wm2 = new WeakMap();
var wm3 = new WeakMap();
var o1 = {name: 'hello'};
var o2 = function(){};
var o3 = window;
// 使用 set 方法添加元素,value 可以是任意值,包括对象、函数甚至另外一个 WeakMap 对象
wm1.set(o1, 'ES6 Wiki');
wm1.set(o2, 10);
wm2.set(o1, o2);
wm2.set(o3, null);
wm2.set(wm1, wm2);
wm1.get(o2); // 10
wm2.get(o2); // undefined,wm2 中没有 o2 这个键
wm2.get(o3); // null
wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (即使值是null)
wm3.set(o1, 'lesson is ES6 Wiki!');
wm3.get(o1); // lesson is ES6 Wiki!
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
<!-- 示例 2 -->
<ul>
<!-- { id:"1", name:"姓名1" } -->
<li>1</li>
<!-- { id:"2", name:"姓名2" } -->
<li>2</li>
<!-- { id:"3", name:"姓名3" } -->
<li>3</li>
</ul>
<script>
const wmap = new WeakMap();
let lis = document.querySelectorAll("li");
for (const li of lis) {
wmap.set(li, {
id: li.innerHTML,
name: `姓名${li.innerHTML}`
});
}
lis[0].remove();
lis = null;
console.log(wmap);
setTimeout(()=>{
console.log(wmap);
},3000);
</script>
ES6+ Set、WeakSet
上一篇