• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2025-04-04 22:07 Aet 隐藏边栏 |   抢沙发  3 
文章评分 1 次,平均分 5.0

文档

  1. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference

Map

概述

  1. 一个带键的数据项的集合,就像一个 Object 一样
  2. 但是它们最大的差别是 Map 允许任何类型的键(key

方法和属性

  1. new Map() —— 创建 map。
  2. map.set(key, value) —— 根据键存储值。
  3. map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined
  4. map.has(key) —— 如果 key 存在则返回 true,否则返回 false
  5. map.delete(key) —— 删除指定键的值。
  6. map.clear() —— 清空 map。
  7. map.size —— 返回当前元素个数

注意

  1. 如我们所见,与对象不同,键不会被转换成字符串。键可以是任何类型
  2. map[key] 不是使用 Map 的正确方式
    1. 虽然 map[key] 也有效,例如我们可以设置 map[key] = 2,这样会将 map 视为 JavaScriptplain object,因此它暗含了所有相应的限制(仅支持 string/symbol 键等)

使用对象作为键

  1. 使用对象作为键是 Map 最值得注意和重要的功能之一

  1. Object 中使用字符串作为键是可以的,但我们无法使用另一个 Object 作为 Object 中的键
    1. 因为 visitsCountObj 是一个对象,它会将所有 Object 键例如上面的 johnben 转换为字符串 "[object Object]"

Map 是怎么比较键的?

  1. Map 使用 SameValueZero 算法来比较键是否相等
  2. 它和严格等于 === 差不多,但区别是 NaN 被看成是等于 NaN。所以 NaN 也可以被用作键

链式调用

  1. 每一次 map.set 调用都会返回 map 本身,所以我们可以进行“链式”调用:

Map迭代

  1. 如果要在 map 里使用循环,可以使用以下三个方法:
    1. map.keys() —— 遍历并返回一个包含所有键的可迭代对象,
    2. map.values() —— 遍历并返回一个包含所有值的可迭代对象,
    3. map.entries() —— 遍历并返回一个包含所有实体 [key, value] 的可迭代对象,for..of 在默认情况下使用的就是这个

  1. 使用插入顺序
    1. 迭代的顺序与插入值的顺序相同。与普通的 Object 不同,Map 保留了此顺序。
  2. 除此之外,Map 有内建的 forEach 方法,与 Array 类似:

Object.entries:从对象创建 Map

  1. 当创建一个 Map 后,我们可以传入一个带有键值对的数组(或其它可迭代对象)来进行初始化,如下所示:

  1. 如果我们想从一个已有的普通对象(plain object)来创建一个 Map,那么我们可以使用内建方法 Object.entries(obj)
    1. 该方法返回对象的键/值对数组,该数组格式完全按照 Map 所需的格式
    2. 这里,Object.entries 返回键/值对数组:[ ["name","John"], ["age", 30] ]

Object.fromEntries:从 Map 创建对象

  1. Object.fromEntries 方法的作用是相反的:给定一个具有 [key, value] 键值对的数组,它会根据给定数组创建一个对象:

  1. 可以使用 Object.fromEntriesMap 得到一个普通对象(plain object
    1. 例如,我们在 Map 中存储了一些数据,但是我们需要把这些数据传给需要普通对象(plain object)的第三方代码
    2. 调用 map.entries() 将返回一个可迭代的键/值对,这刚好是 Object.fromEntries 所需要的格式

  1. 这个代码作用也是一样的
    1. 因为 Object.fromEntries 期望得到一个可迭代对象作为参数,而不一定是数组
    2. 并且 map 的标准迭代会返回跟 map.entries() 一样的键/值对
    3. 因此,我们可以获得一个普通对象(plain object),其键/值对与 map 相同

Set

概述

  1. 一个特殊的类型集合 —— “值的集合”(没有键),它的每一个值只能出现一次
    1. 它的主要特点是,重复使用同一个值调用 set.add(value) 并不会发生什么改变

方法

  1. new Set(iterable) —— 创建一个 set,如果提供了一个 iterable 对象(通常是数组),将会从数组里面复制值到 set 中。
  2. set.add(value) —— 添加一个值,返回 set 本身
  3. set.delete(value) —— 删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false
  4. set.has(value) —— 如果 value 在 set 中,返回 true,否则返回 false
  5. set.clear() —— 清空 set。
  6. set.size —— 返回元素个数

示例

  1. 例如,我们有客人来访,我们想记住他们每一个人

Set迭代

  1. 可以使用 for..offorEach 来遍历 Set

  1. Map 中用于迭代的方法在 Set 中也同样支持:
    1. set.keys() —— 遍历并返回一个包含所有值的可迭代对象,
    2. set.values() —— 与 set.keys() 作用相同,这是为了兼容 Map
    3. set.entries() —— 遍历并返回一个包含所有的实体 [value, value] 的可迭代对象,它的存在也是为了兼容 Map

注意

  1. forEach 的回调函数有三个参数:一个 value,然后是 同一个值 valueAgain,最后是目标对象
  2. forEach 的回调函数有三个参数,是为了与 Map 兼容

WeakMap

概述

  1. 从前面的 垃圾回收章节中知道,JavaScript 引擎在值“可达”和可能被使用时会将其保持在内存中

  1. 通常,当对象、数组之类的数据结构在内存中时,它们的子元素,如对象的属性、数组的元素都被认为是可达的
    1. 例如,如果把一个对象放入到数组中,那么只要这个数组存在,那么这个对象也就存在,即使没有其他对该对象的引用

  1. 类似的,如果我们使用对象作为常规 Map 的键,那么当 Map 存在时,该对象也将存在。它会占用内存,并且不会被(垃圾回收机制)回收

  1. WeakMap 在这方面有着根本上的不同。它不会阻止垃圾回收机制对作为键的对象(key object)的回收

键必须是对象

  1. WeakMapMap 的第一个不同点就是,WeakMap 的键必须是对象,不能是原始值:

  1. 现在,如果我们在 weakMap 中使用一个对象作为键,并且没有其他对这个对象的引用 —— 该对象将会被从内存(和map)中自动清除

方法

  1. WeakMap 不支持迭代以及 keys()values()entries() 方法
    1. 所以没有办法获取 WeakMap 的所有键或值
    2. 为什么会有这种限制呢?
    3. 这是技术的原因
      如果一个对象丢失了其它所有引用(就像上面示例中的 john),那么它就会被垃圾回收机制自动回收
      但是在从技术的角度并不能准确知道 何时会被回收
    4. 这些都是由 JavaScript 引擎决定的
      JavaScript 引擎可能会选择立即执行内存清理,如果现在正在发生很多删除操作,那么 JavaScript 引擎可能就会选择等一等,稍后再进行内存清理
    5. 因此,从技术上讲,WeakMap 的当前元素的数量是未知的
      JavaScript 引擎可能清理了其中的垃圾,可能没清理,也可能清理了一部分
  2. WeakMap 只有以下的方法:
    1. weakMap.get(key)
    2. weakMap.set(key, value)
    3. weakMap.delete(key)
    4. weakMap.has(key)

使用案例:额外数据的存储

  1. WeakMap 的主要应用场景是 额外数据的存储
    1. 假如我们正在处理一个“属于”另一个代码的一个对象,也可能是第三方库,并想存储一些与之相关的数据,那么这些数据就应该与这个对象共存亡 —— 这时候 WeakMap 正是我们所需要的利器
    2. 我们将这些数据放到 WeakMap 中,并使用该对象作为这些数据的键,那么当该对象被垃圾回收机制回收后,这些数据也会被自动清除

  1. 示例2
    1. 例如,我们有用于处理用户访问计数的代码。收集到的信息被存储在 map 中:一个用户对象作为键,其访问次数为值
    2. 当一个用户离开时(该用户对象将被垃圾回收机制回收),这时我们就不再需要他的访问次数了

  1. 现在,john 这个对象应该被垃圾回收,但它仍在内存中,因为它是 visitsCountMap 中的一个键
    1. 当我们移除用户时,我们需要清理 visitsCountMap,否则它将在内存中无限增大
    2. 在复杂的架构中,这种清理会成为一项繁重的任务
    3. 可以通过使用 WeakMap 来避免这样的问题:
      现在我们不需要去清理 visitsCountMap
      john 对象变成不可达时,即便它是 WeakMap 里的一个键,它也会连同它作为 WeakMap 里的键所对应的信息一同被从内存中删除

使用案例:缓存

  1. 另外一个常见的例子是缓存
    1. 我们可以存储(“缓存”)函数的结果,以便将来对同一个对象的调用可以重用这个结果
  2. 为了实现这一点,我们可以使用 Map(非最佳方案):
    1. 对于多次调用同一个对象,它只需在第一次调用时计算出结果,之后的调用可以直接从 cache 中获取
    2. 这样做的缺点是,当我们不再需要这个对象的时候需要清理 cache

  1. 如果我们用 WeakMap 替代 Map,便不会存在这个问题
    1. 当对象被垃圾回收时,对应缓存的结果也会被自动从内存中清除

WeakSet

概述

  1. WeakSet 的表现类似:
    1. Set 类似,但是我们只能向 WeakSet 添加对象(而不能是原始值)
    2. 对象只有在其它某个(些)地方能被访问的时候,才能留在 WeakSet
    3. Set 一样,WeakSet 支持 addhasdelete 方法,但不支持 sizekeys(),并且不可迭代
  2. 变“弱(weak)”的同时,它也可以作为额外的存储空间
    1. 但并非针对任意数据,而是针对“是/否”的事实
    2. WeakSet 的元素可能代表着有关该对象的某些信息

示例

  1. 例如,我们可以将用户添加到 WeakSet 中,以追踪访问过我们网站的用户:

总结

  1. WeakMapWeakSet 最明显的局限性就是不能迭代,并且无法获取所有当前内容
  2. 那样可能会造成不便,但是并不会阻止 WeakMap/WeakSet 完成其主要工作 —— 为在其它地方存储/管理的对象数据提供“额外”存储

Object.keysvaluesentries

概述

  1. 这些方法是通用的,有一个共同的约定来将它们用于各种数据结构
  2. 如果我们创建一个我们自己的数据结构,我们也应该实现这些方法
  3. 它们支持:
    1. Map
    2. Set
    3. Array

普通对象

  1. 对于普通对象,下列这些方法是可用的:
    1. Object.keys(obj) —— 返回一个包含该对象所有的键的数组。
    2. Object.values(obj) —— 返回一个包含该对象所有的值的数组。
    3. Object.entries(obj)—— 返回一个包含该对象所有 [key, value] 键值对的数组
  2. map的区别
    1. 第一个区别是,对于对象我们使用的调用语法是 Object.keys(obj),而不是 obj.keys()
    2. 第二个区别是 Object.* 方法返回的是“真正的”数组对象,而不只是一个可迭代对象
Map Object
调用语法 map.keys() Object.keys(obj),而不是 obj.keys()
返回值 可迭代对象 “真正的”数组

  1. 对于上面的对象user
    1. Object.keys(user) = ["name", "age"]
    2. `Object.values(user) = ["John", 30]
    3. Object.entries(user) = [ ["name","John"], ["age",30] ]

注意

  1. 会忽略 symbol 属性
    1. 就像 for..in 循环一样,这些方法会忽略使用 Symbol(...) 作为键的属性

转换对象

  1. 对象缺少数组存在的许多方法,例如 mapfilter
  2. 如果我们想应用它们,那么我们可以使用 Object.entries,然后使用 Object.fromEntries
    1. 使用 Object.entries(obj)obj 获取由键/值对组成的数组
    2. 对该数组使用数组方法,例如 map,对这些键/值对进行转换
    3. 对结果数组使用 Object.fromEntries(array) 方法,将结果转回成对象

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享