例如,考虑如下代码:
这里发生了什么?和y
这两个对象都被字符串化为"[object Object]"
,所以只有这一个键被设置为m
。
一些人通过在一个值的数组旁边同时维护一个平行的非字符串键的数组实现了山寨的map,比如:
var keys = [], vals = [];
var x = { id: 1 },
y = { id: 2 };
keys.push( x );
vals.push( "foo" );
keys.push( y );
vals.push( "bar" );
keys[0] === x; // true
vals[0]; // "foo"
keys[1] === y; // true
vals[1]; // "bar"
当然,你不会想亲自管理这些平行数组,所以你可能会定义一个数据解构,使它内部带有自动管理的方法。除了你不得不自己做这些工作,主要的缺陷是访问的时间复杂度不再是O(1),而是O(n)。
但在ES6中,不再需要这么做了!使用Map(..)
就好:
var m = new Map();
var x = { id: 1 },
y = { id: 2 };
m.set( x, "foo" );
m.get( x ); // "foo"
m.get( y ); // "bar"
要从一个map中删除一个元素,不要使用delete
操作符,而是使用delete(..)
方法:
使用clear()
你可清空整个map的内容。要得到map的长度(也就是,键的数量),使用size
属性(不是length
)。
m.set( x, "foo" );
m.set( y, "bar" );
m.size; // 2
m.clear();
m.size; // 0
Map(..)
的构造器还可以接受一个可迭代对象(参见第三章的“迭代器”),它必须产生一个数组的列表,每个数组的第一个元素是键,第二元素是值。这种用于迭代的格式与entries()
方法产生的格式是一样的,entries()
方法将在下一节中讲解。这使得制造一个map的拷贝十分简单:
var m2 = new Map( m.entries() );
// 等同于:
var m2 = new Map( m );
因为一个map实例是一个可迭代对象,而且它的默认迭代器与entries()
相同,第二种稍短的形式更理想。
当然,你可以在Map(..)
构造器形式中手动指定一个 entries 列表:
var m = new Map();
var x = { id: 1 },
y = { id: 2 };
m.set( x, "foo" );
var vals = [ ...m.values() ];
vals; // ["foo","bar"]
就像在前一节中讨论过的,你可以使用entries()
(或者默认的map迭代器)迭代一个map的记录。考虑如下代码:
var m = new Map();
var x = { id: 1 },
y = { id: 2 };
m.set( x, "foo" );
m.set( y, "bar" );
var vals = [ ...m.entries() ];
vals[0][0] === x; // true
vals[0][1]; // "foo"
vals[1][0] === y; // true
vals[1][1]; // "bar"
Map 键
要得到键的列表,使用keys()
,它返回一个map中键的迭代器:
要判定一个map中是否拥有一个给定的键,使用has(..)
:
var m = new Map();
var x = { id: 1 },
y = { id: 2 };
m.set( x, "foo" );
m.has( x ); // true
实质上map让你将一些额外的信息(值)与一个对象(键)相关联,而不用实际上将这些信息放在对象本身中。
虽然在一个map中你可以使用任意种类的值作为键,但是你经常使用的将是对象,就像字符串和其他在普通对象中可以合法地作为键的基本类型。换句话说,你可能将想要继续使用普通对象,除非一些或全部的键需要是对象,在那种情况下map更合适。