JavaScript 中的 WeakMap - 简单介绍
WeakMap 是 JavaScript 中最被低估、使用最少的数据结构之一。许多 JavaScript 开发者甚至不知道它的存在。本教程将帮助您理解它。您将了解 WeakMap 是什么、它的工作原理以及它与 Map 的区别。
WeakMap 简介
Map和 WeakMap都是[ES6] 中引入的新数据结构,或者说集合。集合的另一个例子是数组。与数组类似,Map 和 WeakMap 都允许存储数据。对于这些 Map 和 WeakMap,你可以以键值对的形式存储数据。
如果要访问 Map 中存储的值,只需使用正确的 即可key
。WeakMap 也同样适用。访问 WeakMap 中存储的值时,也必须使用正确的key
。Map 和 WeakMap 都允许添加新的键值对并删除现有的键值对。
如果您不确定 Map 或 WeakMap 是否包含特定键,该怎么办?您可以使用一种方法快速检查该键是否存在。因此,Map 和 WeakMap 的工作方式相同。除了这些相似之处外,您还需要了解两者之间的一些重要区别。
Maps 和 WeakMaps 之间的区别
Maps 和 WeakMaps 之间的第一个区别在于可以使用的数据类型。使用 Maps,您可以使用任何您想要的数据类型来为键值对创建键。这也包括对象和函数。但 WeakMaps 则不然。WeakMaps 只允许您使用对象创建键,而不允许使用任何其他数据类型。
这是 Map 和 WeakMap 之间的主要区别之一。另一个重要区别是 WeakMap 中的所有键都是弱引用。这意味着用作 WeakMap 键的对象仍然可能被垃圾回收。当所有对这些对象的引用都消失时,就会发生这种情况。
当程序的任何部分不再使用这些对象时,垃圾回收机制会将它们从内存中释放。需要注意的是,垃圾回收机制不会立即从内存中释放这些对象。这些对象只是被“标记”为可回收对象。
只有当下一个垃圾回收“周期”发生时,它们才会真正被释放。JavaScript 会自动执行这些循环。所以,你不必担心。Map 和 WeakMap 之间的最后一个重大区别是 WeakMap 不可迭代。你不能forEach()
像对 Map 那样使用循环或方法对它们进行迭代。
这也意味着你必须知道你要查找的键。因为我们讨论的是可迭代性。WeakMap 也没有任何size
属性。所以,你实际上并不知道一个键里面有多少个键值对。最后,WeakMap 中没有clear()
方法可以移除所有数据。
这些差异非常重要,并且严重限制了 WeakMap 的使用功能。不过,不要因此而放弃学习,因为 WeakMap 仍然很有用。我们很快会讨论这个问题,但首先,让我们先看看如何创建 WeakMap 以及它们可以做什么。
如何创建 WeakMap
当你想要创建 WeakMap 时,你必须使用WeakMap() 构造函数。这个构造函数会创建一个新的 WeakMap 对象。当你拥有这个对象后,你就可以做任何你想做的事情了。你可以添加新的键值对,检查、检索或删除现有的键值对。
// Create new WeakMap
const myWeakMap = new WeakMap()
WeakMap 方法
默认情况下,WeakMaps 提供了一组方法,使它们的使用更加便捷。这些方法几乎可以实现所有你想做的事情。这些方法是set()
、get()
和。让我们快速浏览一下它们。delete()
has()
添加元素
当你想向 WeakMaps 添加新的键值对时,该set()
方法正是你所需要的。此方法接受两个参数。第一个参数用于key
键值对内部的 ,这将是一个对象。第二个参数用于value
,可以是字符串、数字、布尔值等。
关于该方法,有一件事需要记住set()
。此方法一次只允许您添加一个键值对。如果您想添加多个键值对,则必须多次使用此方法,每个键值对添加一次。
// Create new WeakMap
const myWeakMap = new WeakMap()
// Create some objects
const myObj1 = { name: 'Dexter' }
const myObj2 = { name: 'Jordan' }
const myObj3 = {}
// Add three new key-value pairs
myWeakMap.set(myObj1, 'I am not quite sure about this guy.')
myWeakMap.set(myObj2, 'This is a baller.')
myWeakMap.set(myObj3, 'We fired this guy a month ago.')
// You can also chain set() methods
myWeakMap
.set(myObj1, 'This is first object.')
.set(myObj2, 'This is second object.')
.set(myObj3, 'This is third object.')
检索值
get()
当您想从 WeakMap 中检索值时,您需要的就是该方法。该方法接受一个参数,即您用作要检索的值的键的对象。如果该键存在,则该get()
方法将返回与其关联的值。否则,它将返回undefined
。
// Create new WeakMap
const myWeakMap = new WeakMap()
// Create some objects
const myObj1 = { language: 'JavaScript' }
const myObj2 = { language: 'Python' }
const myObj3 = { language: 'Rust' }
// Add two new key-value pairs
myWeakMap.set(myObj1, 'Language for every platform, soon even a fridge.')
myWeakMap.set(myObj2, 'I kind of miss those curly braces.')
// Retrieve the value associated with "myObj1"
myWeakMap.get(myObj1)
// Output:
// 'Language for every platform, soon even a fridge.'
// Try to retrieve the value associated with "myObj3"
// that was not added to "myWeakMap"
myWeakMap.get(myObj3)
// Output:
// undefined
// Try to retrieve the value associated with non-existing "myObj3"
myWeakMap.get(myObj4)
// Output:
// ReferenceError: myObj3 is not defined
删除元素
从 WeakMaps 中移除元素的最佳(或许也是唯一的)方法是使用delete()
方法。该方法接受一个参数,即键。这是您用作键来存储与其关联的值的对象。如果 WeakMap 对象中的元素对已成功移除,则此方法将返回true
或false
。true
如果该键值对未被移除,它将返回false
。如果 WeakMap 中不存在该键,你也会得到false
。如果你尝试作为键传入的对象实际上不是一个对象,也会发生同样的情况。
// Create new WeakMap
const myWeakMap = new WeakMap()
// Create some objects
const myObj1 = { language: 'JavaScript' }
const myObj2 = { language: 'Python' }
const myObj3 = {}
// Add two new key-value pairs
myWeakMap.set(myObj1, 'Semicolons or not?')
myWeakMap.set(myObj2, 'White space matters.')
// Remove the value associated with "myObj2"
myWeakMap.delete(myObj2)
// Output:
// true
// Try to remove the value associated with "myObj2" again
myWeakMap.delete(myObj2)
// Output:
// false
// Try to use "myObj3" that is not in myWeakMap
myWeakMap.delete(myObj2)
// Output:
// false
检查现有密钥
您知道如何添加、检索和移除值。最后一步是检查 WeakMap 中是否存在某个键。您可以使用has()
方法来做到这一点。此方法接受一个参数,即您想要知道是否将其用作 的对象key
。如果key
存在,则该has()
方法返回true
。否则,返回false
。
// Create new WeakMap
const myWeakMap = new WeakMap()
// Create some objects
const myObj1 = { language: 'PHP' }
const myObj2 = { language: 'Pearl' }
// Check if "myObj1" is used as a key in "myWeakMap"
myWeakMap.set(myObj1, 'Not that dead yet.')
// Output:
// true
// Check if "myObj1" is used as a key in "myWeakMap"
myWeakMap.has(myObj1)
// Output:
// true
// Check if "myObj2" is used as a key in "myWeakMap"
myWeakMap.has(myObj2)
// Output:
// false
WeakMaps 的潜在用例
WeakMap 乍一看可能没什么用,再看可能也一样。但这并不意味着它们一无是处。确实,当你需要存储一些数据时,它们并非最佳选择。其他集合,例如数组、对象、Map 或 Set,会更好地完成这项工作。
WeakMaps 非常适合用于需要为对象添加一些附加值的情况。如果您尝试使用 Maps 来实现这一点,则会阻止这些对象被垃圾回收。这会导致性能下降和内存泄漏。但 WeakMaps 不会出现这种情况,因为它们不会阻止垃圾回收。
如果你将某个对象添加到 WeakMap 中,之后又删除了对该对象的所有引用,该对象将被垃圾回收。在这种情况下以及类似的场景下使用 WeakMap 还有另一个潜在的好处。WeakMap 本质上是黑盒子。你无法迭代它们来获取它们所包含的元素,也无法获取它们的大小。
这意味着你必须知道要使用哪个对象作为键才能获取特定的值。否则,你将无法获取到它。另外值得一提的是,它缺乏任何清除方法。你无法一次性从 WeakMap 中删除所有元素。你只能一次删除一个,并且必须知道要使用哪个键。
从这个角度来看,WeakMap 可以提供其他集合或数据结构无法提供的更高安全性。如果考虑到垃圾回收机制,这种安全性优势将更加显著。删除对某个对象的所有引用,所有与该对象关联的“敏感”数据迟早也会消失。
结论:JavaScript 中的 WeakMap - 简单介绍
WeakMaps 是 JavaScript 中鲜为人知的特性之一。诚然,它们并非存储数据的最佳选择。然而,WeakMaps 更适合处理某些任务。例如,向对象添加一些额外的元数据。WeakMaps 在这方面做得相当不错。
我希望本教程能帮助您了解什么是 WeakMaps、它们如何工作、它们与 Maps 和其他集合有何不同以及如何使用它们。
鏂囩珷鏉ユ簮锛�https://dev.to/alexdevero/weakmap-in-javascript-an-easy-introduction-bkj