Map

  1. Map 是有序无重复的数据结构,“键” 的范围不限于字符串,各种类型的值 (包括对象) 都可以当作键,键是根据添加的顺序决定的;初始化 Map 对象时,如果默认参数的数组中超过两个以上的值不会被 Map 对象读取;

  2. 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 取值

基本使用

JavaScript
JavaScript
JavaScript
// 创建一个非空 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

  1. MapObject 有非常多的相似的地方,Map 的出现也是为了弥补 Object 的不足;

  2. Object 的键只能是字符串,Map 的键可以是任意类型的值 (包括对象),所以 Map 是一种更完善的 Hash 结构实现;

判断键值相等的问题

  1. NaN 是与 NaN 相等的 (虽然 NaN !== NaN),剩下所有其它的值是根据 === 运算符的结果判断是否相等;

  2. 在目前的 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

  1. WeakMapkey 只能是对象,值可以是任意类型的,和 WeakSet 一样 WeakMapkey 的引用是弱引用,如果没有其他对象引用,GC 会对该对象进行回收;

  2. WeakMapkey 是基本类型数据时就会报错;

方法

方法名 描述
set() 接收键值对,向 WeakMap 实例中添加元素
get() 传入指定的 key 获取 WeakMap 实例上的值
has() 传入指定的 key 查找在 WeakMap 实例中是否存在
delete() 传入指定的 key 删除 WeakMap 实例中对应的值

示例

JavaScript
html
// 示例 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>
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. Map
    1. 1.1. Map 属性和方法
    2. 1.2. 基本使用
    3. 1.3. Map VS Object
    4. 1.4. 判断键值相等的问题
    5. 1.5. 手写 map
  2. 2. WeakMap
    1. 2.1. 方法
    2. 2.2. 示例