ES6 - Map的用法

前言: 最近在公司些项目时,多次用到Map函数,故来重新学习,温故而知新
map 是 JavaScript ES6新出的语法,可以帮助我们更好的操作 对象

Map

介绍

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值

Map 对象是键值对的集合。Map 中的一个键只能出现一次;它在 Map 的集合中是独一无二的。Map 对象按键值对迭代——一个 for…of 循环在每次迭代后会返回一个形式为 [key,value] 的数组

简单的使用

  const map1 = new Map();

  map1.set('a', 1);
  map1.set('b', 2);
  map1.set('c', 3);
  // map取值
  console.log(map1.get('a')); // 1
  // 可以覆盖
  map1.set('a', 97);
  console.log(map1.get('a')); // 97
  // 类似 数组的 length
  console.log(map1.size); // 3
  // map 删除
  map1.delete('b');
  console.log(map1.size); // 2

Object 和 Map 的比较

Map Object
意外的键 Map 默认情况不包含任何键。只包含显式插入的键 一个 Object 有一个原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突
键的类型 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 一个 Object 的键必须是一个 String 或是 Symbol
键的顺序 Map 中的键是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值 虽然 Object 的键目前是有序的,但并不总是这样,而且这个顺序是复杂的。因此,最好不要依赖属性的顺序。
Size Map 的键值对个数可以轻易地通过 size 属性获取 Object 的键值对个数只能手动计算
迭代 Map 是 可迭代的 的,所以可以直接被迭代 Object 没有实现 迭代协议,所以使用 JavaSctipt 的 for…of 表达式并不能直接迭代对象
性能 在频繁增删键值对的场景下表现更好 在频繁添加和删除键值对的场景下未作出优化

实例属性

Map.prototype.size

返回 Map 对象中的键值对数量。

const map = new Map()
map.size

实例方法

Map.prototype.clear()

移除 Map 对象中所有的键值对。

const myMap = new Map();
myMap.set('bar', 'baz');
myMap.set(1, 'foo');
console.log(myMap.size);  // 2

myMap.clear();

console.log(myMap.size);  // 0

Map.prototype.delete()

移除 Map 对象中指定的键值对,如果键值对存在并成功被移除,返回 true,否则返回 false。调用 delete 后再调用 map.has(key) 将返回 false

  const myMap = new Map();
  myMap.set("bar", "foo");
  console.log(myMap.delete("bar")); // 返回 true。成功地移除元素
  console.log(myMap.has("bar"));    // 返回 false。"bar" 元素将不再存在于 Map 实例中
  console.log(myMap.size) // 0
  console.log(myMap.get('bar')) // undefined

Map.prototype.get()

返回与指定的键 key 关联的值,若不存在关联的值,则返回 undefined

  const myMap = new Map();
  myMap.set("bar", "foo");
  console.log(myMap.get('bar')) // foo
  myMap.delete("bar")
  console.log(myMap.get('bar')) // undefined

Map.prototype.has()

返回一个布尔值,用来表明 Map 对象中是否存在与指定的键 key 关联的值

const myMap = new Map();
myMap.set("bar", "foo");

console.log(myMap.has("bar"));  // true
console.log(myMap.has("baz"));  // false

Map.prototype.set()

在 Map 对象中设置与指定的键 key 关联的值,并返回 Map 对象

const myMap = new Map();

// 将一个新元素添加到 Map 对象
myMap.set('bar', 'foo');
myMap.set(1, 'foobar');

// 在 Map 对象中更新某个元素的值
myMap.set('bar', 'baz');

// 链式调用添加元素
myMap.set('bar', 'foo')
  .set(1, 'foobar')
  .set(2, 'baz');

Map.prototype[@@iterator]()

返回一个新的迭代对象,其为一个包含 Map 对象中所有键值对的 [key, value] 数组,并以插入 Map 对象的顺序排列

  var myMap = new Map();
  myMap.set('0', 'foo');
  myMap.set(1, 'bar');
  myMap.set({}, 'baz');

  var mapIter = myMap[Symbol.iterator]();
  //返回的其实是个 generator
  console.log(mapIter.next().value); // ["0", "foo"]
  console.log(mapIter.next().value); // [1, "bar"]
  console.log(mapIter.next().value); // [Object, "baz"]
  // for of
  for (const entry of myMap) {
    console.log(entry);
    // ["0", "foo"]
    // [1, "bar"]
    // [{}, "baz"]
  }

Map.prototype.keys()

返回一个新的迭代对象,其中包含 Map 对象中所有的键,并以插入 Map 对象的顺序排列

  var myMap = new Map();
  myMap.set('0', 'foo');
  myMap.set(1, 'bar');
  myMap.set({}, 'baz');
  
  const mapIter = myMap.keys();
  
  console.log(mapIter.next().value); // 0
  console.log(mapIter.next().value); // 1
  console.log(mapIter.next().value); // {}
  
  for (const entry of myMap.keys()) {
    console.log(entry);
    // 0
    // 1
    // {}
  }

  for (const entry of mapIter) {
    console.log(entry); // 打印不出来
  }

Map.prototype.values()

返回一个新的迭代对象,其中包含 Map 对象中所有的值,并以插入 Map 对象的顺序排列

  const myMap = new Map();
  myMap.set('0', 'foo');
  myMap.set(1, 'bar');
  myMap.set({}, 'baz');

  const mapIter = myMap.values();

  console.log(mapIter.next().value); // "foo"
  console.log(mapIter.next().value); // "bar"
  console.log(mapIter.next().value); // "baz"

  for (const entry of myMap.values()) {
    console.log(entry);
    // foo
    // bar
    // baz
  }

  for (const entry of mapIter) {
    console.log(entry); // 打印不出来
  }

Map.prototype.entries()

返回一个新的迭代对象,其为一个包含 Map 对象中所有键值对的 [key, value] 数组,并以插入 Map 对象的顺序排列

  const myMap = new Map();
  myMap.set("0", "foo");
  myMap.set(1, "bar");
  myMap.set({}, "baz");

  const mapIter = myMap.entries();

  console.log(mapIter.next().value); // ["0", "foo"]
  console.log(mapIter.next().value); // [1, "bar"]
  console.log(mapIter.next().value); // [Object, "baz"]

  console.log(myMap.entries(), mapIter); // MapIterator {'0' => 'foo', 1 => 'bar', {…} => 'baz'}  MapIterator {}
  
  for (const entry of myMap.entries()) {
    console.log(entry);
    // ["0", "foo"]
    // [1, "bar"]
    // [{}, "baz"]
  }

  for (const entry of mapIter) {
    console.log(entry); // 打印不出来
  }

Map.prototype.forEach()

以插入的顺序对 Map 对象中存在的键值对分别调用一次 callbackFn。如果给定了 thisArg 参数,这个参数将会是回调函数中 this 的值

  const myMap = new Map();
  myMap.set("0", "foo");
  myMap.set(1, "bar");
  myMap.set({}, "baz");

  myMap.forEach((value, key, map) => {
    console.log(value, key, map);
    // foo 0 可迭代的 map 
    // bar 1 可迭代的 map 
    // baz {} 可迭代的 map 
    for (const inter of map) {
      console.log(inter);
      //["0", "foo"]
      //[1, "bar"]
      //[{}, "baz"]
    }
  })

示例

将 NaN 作为 Map 的键

NaN 也可以作为 Map 对象的键。虽然 NaN 与任何值甚至与自己都不相等(NaN !== NaN 返回 true),但是因为所有的 NaN 的值都是无法区分的,所以下面的例子成立:

const myMap = new Map();
myMap.set(NaN, 'not a number');

myMap.get(NaN);
// "not a number"

const otherNaN = Number('foo');
myMap.get(otherNaN);
// "not a number"

使用 for…of 方法迭代 Map

Map 可以使用 for…of 循环来实现迭代:

const myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');

for (const [key, value] of myMap) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

for (const key of myMap.keys()) {
  console.log(key);
}
// 0
// 1

for (const value of myMap.values()) {
  console.log(value);
}
// zero
// one

for (const [key, value] of myMap.entries()) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

使用 forEach() 方法迭代 Map

myMap.forEach((value, key) => {
  console.log(`${key} = ${value}`);
});
// 0 = zero
// 1 = one

Map 与数组的关系

const kvArray = [['key1', 'value1'], ['key2', 'value2']];

// 使用常规的 Map 构造函数可以将一个二维键值对数组转换成一个 Map 对象
const myMap = new Map(kvArray);

console.log(myMap.get('key1')); // "value1"

// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
console.log(Array.from(myMap)); // 输出和 kvArray 相同的数组

// 更简洁的方法来做如上同样的事情,使用展开运算符
console.log([...myMap]);

// 或者在键或者值的迭代器上使用 Array.from,进而得到只含有键或者值的数组
console.log(Array.from(myMap.keys())); // 输出 ["key1", "key2"]

复制或合并 Maps

// Map 能像数组一样被复制:
const original = new Map([
  [1, 'one'],
]);

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false. 浅比较 不为同一个对象的引用

//Map 对象间可以进行合并,但是会保持键的唯一性。
const first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

const second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的。
// 展开语法本质上是将 Map 对象转换成数组。
const merged = new Map([...first, ...second]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

// Map 对象也能与数组合并:

const first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

const second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// Map 对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。
const merged = new Map([...first, ...second, [1, 'eins']]);

console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

你可能感兴趣的:(javascript,es6,javascript,前端)