如果您关注本系列有关ECMAScript 6的文章,您已经了解了一些可用于String和Array类型的新方法。 JavaScript的新版本也引入了几种新的数据类型。 在本文中,我们将讨论Map及其弱项WeakMap 。
请记住,如果要填充本教程中要介绍的内容,可以使用Paul Miller的 es6-shim 。
Map
映射是编程中最常用的数据结构之一。 映射是将键与值相关联的对象,而与值的类型(数字,字符串,对象等)无关。 对于那些不了解地图的人,让我们讨论一个简短的示例。 在典型的结构化数据库表中,将ID与每个条目(表的一行)相关联。 因此,您有类似以下内容:
ID 1 -> Aurelio De Rosa, Italy ID 2 -> Colin Ihrig, USA ID 3 -> John Doe, USA
在Java和C#等语言中,您都有一个类,可让您实例化地图。 在其他语言(如PHP)中,您可以使用关联数组创建地图。 在ECMAScript 6之前,JavaScript是缺少此数据结构的语言之一。 现在,该数据类型存在,称为Map
。
JavaScript映射非常强大,因为它们允许将任何值(对象和原始值)用作键或值。 与使用Object
类型创建的地图相比,这是最重要的区别之一。 实际上,使用对象文字创建的映射仅允许将字符串作为其键。 此外,稍后我们将看到, Map
类型具有一种可以轻松检索其中包含的元素数量的方法,而对于对象,则必须手动遍历它们,检查该元素是否属于对象本身,并且它不是继承的(使用旧的hasOwnProperty()
)。
现在,我已经向您介绍了这种新的数据类型,让我们发现什么是可用的属性和方法。
Map.prototype.size
size
属性返回Map
对象中元素的数量。 我在上一节中提到过,这是一个很好的补充,因为有了它,您不必自己计算元素。
Map.prototype.constructor()
Map
对象的构造函数用于实例化新对象,并接受称为iterable
的可选参数。 后者是一个数组或可迭代对象,其元素是键/值对(两个元素的数组)。 这些元素中的每一个都将添加到新地图中。 例如,您可以编写:
var array = [['key1', 'value1'], ['key2', 100]];
var map = new Map(array);
Map.prototype.set()
set()
方法用于向地图添加新元素(键/值对)。 如果使用的密钥已经存在,则关联的值将被新的密钥替换。 其签名如下:
Map.prototype.set(key, value)
其中key
是您要使用的密钥, value
是要存储的值。 此方法修改了它所调用的地图,但也返回了新的地图。
目前,此方法已在Firefox,Internet Explorer 11,Chrome和Opera中带标志(“启用实验性JavaScript”)后面实现。
Map.prototype.get()
get()
方法返回与提供的键关联的值。 如果找不到键,则该方法返回undefined
。 该方法的签名如下所示,其中key
是要使用的密钥。
Map.prototype.get(key)
目前,此方法已在Firefox,Internet Explorer 11,Chrome和Opera中带标志(“启用实验性JavaScript”)后面实现。
Map.prototype.delete()
delete()
方法从映射中删除与提供的键关联的元素。 如果成功删除了元素,则返回true
否则返回false
。 该方法的签名如下所示:
Map.prototype.delete(key)
key
表示要删除的元素的键。
该方法当前在Firefox,Internet Explorer 11,Chrome和Opera中实现(您必须激活通常的标志)。
Map.prototype.has()
has()
是一种验证具有给定键的元素是否存在的方法。 如果找到密钥,则返回true
否则返回false
。 该方法的签名如下所示:
Map.prototype.has(key)
key
是您要搜索的键。
目前,此方法已在Firefox,Internet Explorer 11,Chrome和Opera中带标志(“启用实验性JavaScript”)后面实现。
Map.prototype.clear()
clear()
方法是从Map
对象中删除所有元素的便捷方法。 该方法没有返回值(这意味着它返回undefined
)。 clear()
的签名如下所示:
Map.prototype.clear()
clear()
当前在Firefox,Internet Explorer 11,Chrome和Opera中通常的标志后面实现。
Map.prototype.forEach()
正如我们可以遍历数组,使用forEach()
方法执行回调函数一样,使用映射也可以做到这一点。 forEach()
的签名如下所示:
Map.prototype.forEach(callback[, thisArg])
callback
是对映射中的每个元素执行的回调函数,并且thisArg
用于设置回调的上下文( this
)。 该方法没有返回值(这意味着它返回undefined
)。 callback
接收三个参数,分别是:
-
value
:处理的元素的值 -
key
:已处理元素的键 -
map
:正在处理的Map
对象
Firefox,Internet Explorer 11以及带有标志的Chrome和Opera支持此方法。
Map.prototype.entries()
entries()
是一种获取Iterator
对象以遍历地图元素的方法。 在谈论Array类型的新keys()方法时,我已经提到过这种类型的对象。 此方法的签名是:
Map.prototype.entries()
Firefox以及标记后面的Chrome和Opera目前支持此方法。
Map.prototype.keys()
keys()
方法与entries()
非常相似,但是它仅返回元素的键。 其签名如下:
Map.prototype.keys()
Firefox以及标记后面的Chrome和Opera目前支持此方法。
Map.prototype.values()
与keys()
类似,我们有values()
。 它返回一个Iterator
对象,该对象包含地图元素的值。 其签名如下:
Map.prototype.values()
Firefox以及标记后面的Chrome和Opera目前支持此方法。
WeakMap
WeakMap
与Map
非常相似,但有一些重要的区别。 首先是WeakMap
仅接受对象作为键。 这意味着{}
, function(){}
(请记住函数是从Object
继承的),并且允许您自己的类的实例,但不允许'key'
, 10
和其他原始数据类型。
另一个重要的区别是,如果没有其他充当键的对象的引用(引用为弱 ),则WeakMap
对象不会阻止垃圾回收。 由于存在这种差异,因此没有方法可以一次检索键(例如Map
的Map.prototype.keys()
方法)或一次检索多个元素(例如Map.prototype.values()
和Map.prototype.entries()
)。 Mozilla开发人员网络(MDN)很好地解释了原因:
WeakMap密钥不可枚举(即,没有方法可以为您提供密钥列表)。 如果是这样,则该列表将取决于垃圾收集的状态,从而引入不确定性。
上一点的进一步结果是,没有可用的size
属性。
同样值得注意的是,Chrome 37和Opera 24(在撰写本文时为最新的稳定器)支持WeakMap
及其方法而没有标志,而Map
则不是如此。
全部放在一起
到目前为止,您已经了解了有关Map
和WeakMap
数据类型及其方法的所有知识。 在本节中,我们将使它们起作用,以便您可以更好地了解它们的功能。 除了向您展示一些代码外,我们还将为您提供演示,以便您可以实时进行演示。
在第一个演示中,我们将看到一个Map
对象及其方法。
// Creates a new Map object
var mapObj = new Map();
// Defines an object that will be used a key in the map
var objKey = {third: 'c'};
// Adds a new element having a String as its key and a String as its value
mapObj.set('first', 'a');
// Adds a new element having a Number as its key and an Array as its value
mapObj.set(2, ['b']);
// Adds a new element having an Object as its key and a Number as its value
mapObj.set(objKey, 3);
// Adds a new element having an Array as its key and a String as its value
mapObj.set(['crazy', 'stuff'], 'd');
// Checks whether an element having a key of "2" exists in the map. Prints "true"
console.log(mapObj.has(2));
// Checks whether an element having a key of "test" exists in the map. Prints "false"
console.log(mapObj.has('test'));
// Retrieves the element having key of "first". Prints "a"
console.log(mapObj.get('first'));
// Retrieves the element having key of "['crazy', 'stuff']". Prints "undefined" because even if the value of this array are identical to the one used to set a value, they are not the same array
console.log(mapObj.get(['crazy', 'stuff']));
// Retrieves the element having as a key the value of objKey. Prints "3" because it's exactly the same object using to set the element
console.log(mapObj.get(objKey));
// Retrieves the element having key of "empty". Prints "undefined"
console.log(mapObj.get('empty'));
// Retrieves the map size. Prints "4"
console.log(mapObj.size);
// Deletes the element having key of "first". Prints "true"
console.log(mapObj.delete('first'));
// Retrieves the map size. Prints "3"
console.log(mapObj.size);
// Loops over each element of the map
mapObj.forEach(function(value, key, map) {
// Prints both the value and the key
console.log('Value ' + value + ' is associated to key ' + key);
});
var entries = mapObj.entries();
var entry = entries.next();
// Loops over each element of the map
while(!entry.done) {
// Prints both the value and the key
console.log('Value ' + entry.value[1] + ' is associated to key ' + entry.value[0]);
entry = entries.next();
}
var values = mapObj.values();
var value = values.next();
// Loops over each value of the map
while(!value.done) {
// Prints the value
console.log('Value: ' + value.value);
value = values.next();
}
var keys = mapObj.keys();
var key = keys.next();
// Loops over each key of the map
while(!key.done) {
// Prints the key
console.log('Key: ' + key.value);
key = keys.next();
}
// Deletes all the elements of the map
mapObj.clear();
// Retrieves the map size. Prints "0"
console.log(mapObj.size);
下面显示了先前代码的实时演示,并且还可以作为JSFiddle获得 。
在第二个演示中,我们将看到如何使用WeakMap
对象。
// Creates a new WeakMap object
var weakMapObj = new WeakMap();
// Defines an object that will be used a key in the map
var objKey1 = {a: 1};
// Defines another object that will be used a key in the map
var objKey2 = {b: 2};
// Adds a new element having an Object as its key and a String as its value
weakMapObj.set(objKey1, 'first');
// Adds a new element having an Object as its key and a String as its value
weakMapObj.set(objKey2, 'second');
// Adds a new element having a Function as its key and a Number as its value
weakMapObj.set(function(){}, 3);
// Checks whether an element having as its key the value of objKey1 exists in the weak map. Prints "true"
console.log(weakMapObj.has(objKey1));
// Retrieve the value of element associated with the key having the value of objKey1. Prints "first"
console.log(weakMapObj.get(objKey1));
// Deletes the element having key of objKey1. Prints "true"
console.log(weakMapObj.delete(objKey1));
// Deletes all the elements of the weak map
weakMapObj.clear();
下面显示了先前代码的实时演示,并且还可以作为JSFiddle获得 。
结论
在本教程中,我介绍了新的Map
和WeakMap
数据类型。 前者是该语言的不错的补充,因为大多数开发人员已经很长时间模拟了地图。 它的弱项实际上并不是您在日常工作中会经常使用的东西,但是在某些情况下肯定会很合适。 为了加强讨论的概念,我强烈建议您使用提供的演示。 玩得开心!