JavaScript Map数据类型

1、定义

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

1.1、基本类型

在 JavaScript 中,基本类型(基本数值、基本数据类型)是一种既非对象无方法或属性的数据。有 7 种原始数据类型:

  • string
  • number
  • bigint
  • boolean
  • undefined
  • symbol
  • null

2、描述

Map 对象是键值对的集合。

Map 中的一个键只能出现一次;它在 Map 的集合中是独一无二的。

规范要求 Map 实现 “平均访问时间与集合中的元素数量呈次线性关系” 。因此,它可以在内部表示为哈希表(使用 O(1) 查找)、搜索树(使用 O(log(N)) 查找)或任何其他数据结构,只要复杂度小于 O(N)。

3、键的相等

键的比较基于零值相等算法。(它曾经使用同值相等,区别在于同值相等将 0 和 -0 视为不同)

这意味着 NaN 是与 NaN 相等的(虽然 NaN !== NaN),剩下所有其他的值是根据 === 运算符的结果判断是否相等。

4、Object 和 Map 的比较

MapObject
意外的键Map 默认情况不包含任何键。只包含显式插入的键一个 Object 有一个原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突(备注:虽然可以用 Object.create(null)来创建一个没有原型的对象,但是这种用法不太常见)
键的类型一个 Map 的键可以是任意值,包括函数、对象或任意基本类型一个 Object 的键必须是一个 String 或是 Symbol
键的顺序Map 中的键是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值虽然 Object 的键目前是有序的,但并不总是这样,而且这个顺序是复杂的(因此,最好不要依赖属性的顺序)
SizeMap 的键值对个数可以轻易地通过 size 属性获取Object 的键值对个数只能手动计算
迭代Map 是可迭代的Object 没有实现迭代协议,所以使用 JavaSctipt 的 for...of] 表达式并不能直接迭代对象(备注:对象可以实现迭代协议,或者你可以使用 Object.keysObject.entriesfor...in
性能在频繁增删键值对的场景下表现更好在频繁添加和删除键值对的场景下未作出优化
序列化和解析没有元素的序列化和解析的支持ObjectJSON 的序列化使用 JSON.stringfy();由 JSONObject 的解析使用 JSON.parse()

5、设置对象属性

设置对象属性同样适用于 Map 对象,但会产生一些问题,下面用实例来演示:

// 这里可能会有一些疑问:为什么 map 使用 const 定义的却还能进行更改
// 原因是:const 判断变量是判断变量地址是否改变,而复杂数据类型中元素的改变并没有改变地址
const map = new Map();
map['a'] = 1;
console.log(map); // Map { a: 1 }

若对变量赋值传址还是传值有疑惑可以点击这里进行查看

但这种设置属性的方式不会改变 Map 的数据结构。它使用的是通用对象的特性。‘a’ 的值未被存储在 Map 中,无法被查询到。其他的对这一数据的操作也会失败:

console.log(map.has('a')); // false——表示map不存在'a'键
console.log(map.delete('a')); // false——表示删除键为'a'的键值对失败
console.log(map); // Map { a: 1 }

正确的存储到 Map 中的方式是使用 set(key, value) 方法,下面会详细的讲到。

6、Map的构造函数

通过 new Map() 的方法创建一个 Map 对象。

// new Map():创建一个空 Map
var map = new Map();

// new Map(iterable):创建一个带默认值的 Map
// iterable:键值对的数组([[1, 'one'], [2, 'two']])或 其他可迭代对象
var map = new Map(iterable);

注意:Map() 只能用 new 构造。尝试不使用 new 调用它会抛出 TypeError。

7、Map的属性

通过 size 属性来获取 Map 的键值对数量。

// size:返回 Map 的键值对数量
var map = new Map([[1, 'one'], [2, 'two']]);
console.log(map.size); // 2

size 属性的值是一个整数,表示 Map 对象有多少个键值对。size 是只读属性,用 set 方法修改 size 返回 undefined,即不能改变它的值。

8、Map的方法

8.1、set(key, value)

通过 set(key, value) 方法向 Map 中添加(或修改)一个键值对。(返回修改后的 Map 对象)

// set(key, value):向 Map 中添加(或修改)一个键值对
// key:键值对的键
// value:键值对的值
var map = new Map();

// 如果遇到不存在的键则添加新键值对
console.log(map.set('a', 1)); // Map{'a' => 1}

// 如果遇到存在的键则修改值
console.log(map.set('a', 2)); // Map{'a' => 2}

除了上述写法外,set(key, value) 还有一种链式调用的方法,同样返回修改后的 Map 对象,下面进行实例展示:

// set 的链式调用
var map = new Map();
console.log(map.set(['a', 1]).set(['b', 2])); // Map{ 'a': 1, 'b': 2 }

8.2、get(key)

通过 get(key) 方法获取 Map 的指定键的值。(返回对应值)

// get(key):获取 Map 的指定键的值
// key:键值对的键
var map = new Map([['a', 1]]);
console.log(map.get('a')); // 1

如果值是复杂数据类型(数组、对象等),可能会存在内存泄露的问题。

const arr = [];
const map = new Map();
map.set('bar', arr); // 此时的 arr 传的是栈内存中的地址
map.get('bar').push('foo');
console.log(arr); // ["foo"]
console.log(map.get('bar')); // ["foo"]

注意:持有原始对象引用的映射实际上意味着对象不能被垃圾回收,这可能会导致意外的内存问题。如果你希望存储在映射中的对象具有与原始对象相同的生命周期,请考虑使用 WeakMap。

8.3、has(key)

通过 has(key) 判断 Map 中是否存在指定键的键值对。(返回布尔值)

// has(key):判断 Map 中是否存在指定键的键值对
// key:键值对的键
var map = new Map([['a', 1]]);
console.log(map.has('a')); // 存在返回 true
console.log(map.has('b')); // 不存在返回 false

8.4、delete(key)

通过 delete(key) 移除 Map 中指定键的键值对。(返回布尔值)

// delete(key):移除 Map 中指定键的键值对
// key:键值对的键
var map = new Map([['a', 1]]);
console.log(map.delete('a')); // 删除成功返回 true
console.log(map.delete('a')); // 删除失败返回 false

8.5、clear()

通过 clear() 移除 Map 中所有的键值对。(返回 undefined)

// clear():移除 Map 中所有的键值对
var map = new Map([['a', 1]]);
console.log(map.clear()); // undefined

8.6、keys()

通过 keys() 获取 Map 中所有的键。(返回 MapIterator)

// keys():获取 Map 中所有的键
var map = new Map([['a', 1]]);
console.log(Array.from(map.keys())); // ['a']

建议配合 Array.from() 使用,下面的 values()entries() 同样。
若对数组方法 Array.from() 不了解可以点击这里查看

8.7、values()

通过 values() 获取 Map 中所有的值。(返回 MapIterator)

// values():获取 Map 中所有的值
var map = new Map([['a', 1]]);
console.log(Array.from(map.values())); // [1]

8.8、entries()

通过 entries() 获取 Map 中所有的键值对。(返回 MapIterator)

// entries():获取 Map 中所有的键值对
var map = new Map([['a', 1]]);
console.log(Array.from(map.entries())); // [['a', 1]]

9、迭代

9.1、for…of

var map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const value of map) {
  console.log(value);
}
// ['a', 1]
// ['b', 2]
// ['c', 3]

9.2、forEach

var map = new Map([['a', 1], ['b', 2], ['c', 3]]);
map.forEach((item, index) => {
  console.log(index + ' : ' + item);
})
// a : 1
// b : 2
// c : 3

若对 forEach 有异或可以点击这里查看

9.3 迭代器

var map = new Map([['a', 1], ['b', 2]]);
// 获取迭代器
const iterator = map.entries();
console.log(iterator.next().value); // ["a", 1]
console.log(iterator.next().value); // ["b", 2]
  • 感谢你这么帅还关注了我!!!(记得一键三连)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackson Mseven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值