JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值对
但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。 为了解决这个问题,ES6规范引入了新的数据类型Map

var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]); //这是个object对象
m.get('Michael'); // 95 
var m = new Map(); // 空Map 
m.set('Adam', 67); // 添加新的key-value 
m.set('Bob', 59); 
m.has('Adam'); // 是否存在key 'Adam': true 
m.get('Adam'); // 67 
m.delete('Adam'); // 删除key 'Adam' 
m.get('Adam'); // undefined 不存在

由于一个key只能对应一个value,所以,多次对一个key放入value,会把值更新为后面的值

var m = new Map(); 
m.set('Adam', 67); 
m.set('Adam', 88); 
m.get('Adam'); //88

Set和Map类似,也是一组key的集合,但不存储value,由于key不能重复,所以,在Set中,没有重复的值,重复元素在Set中自动被过滤
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:

var s1 = new Set(); // 空Set 
var s2 = new Set([1, 2, 3]); // 含1, 2, 3 
var s = new Set([1, 2, 3, 3, '3']); 
s; // Set {1, 2, 3, "3"}"3"和3不同

通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果

s.add(4) 
 s ;//{1, 2, 3, 4} 
s.add(4) 
 s ;//{1, 2, 3, 4}

通过delete(key)方法可以删除元素:

var s = new Set([1, 2, 3]); 
s; // Set {1, 2, 3} 
s.delete(3); 
s; // Set {1, 2}

控制台返回错误信息Error:Not a number

throw 'Not a number'; //Error:Not a number

遍历Array可以采用下标循环,遍历Map和Set就无法使用下标
为了统一集合类型,ES6标准引入了新的iterable类型,Array、Map和Set都属于iterable类型
具有iterable类型的集合可以通过新的for … of循环来遍历
用for … of循环遍历集合,用法如下

var a = ['A', 'B', 'C']; 
var s = new Set(['A', 'B', 'C']); 
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); 

for (var x of a)
 {  console.log(x); };//A B C

for (var x of s) {console.log(x); };//A B C

for (var x of m) {console.log(x[0] + '=' + x[1]); };//1=x 2=y3=z

注意Map遍历的时候,每一个Map的元素相当于是个数组,一个是Key,一个是Value,对应着x[0]和x[1]

for … of循环和for … in循环有何区别?
for … in循环由于历史遗留问题,它遍历的实际上是对象的属性名称(key)
一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性,当我们手动给Array对象添加了额外的属性后,for … in循环将带来意想不到的意外效果

var a = ['A', 'B', 'C'];
a.name="hello";
for (var x in a) { console.log(x); }0 1 2 name
for (var x in a) { console.log(a[x]); };//AB C hello

for … in循环将把name包括在内,但Array的length属性却不包括在内,所以如果用for…in循环可能会出现问题

for … of循环则完全修复了这些问题,它只循环集合本身的元素

var a = ['A', 'B', 'C']; 
a.name = 'Hello'; 
for (var x of a) { console.log(x); };//A B C

更好的方式是直接使用iterable内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数
以Array为例 ,因为组成array的是element(元素本身 ),index(索引),array(数组对象)
function()内的顺序就是按着元素,索引,数组,传入的变量名可以修改,(这里只是方便大家理解)

var a = ['A', 'B', 'C']; 
a.forEach(function (element, index, array)
 { 
console.log(element);
}); 
A 
B 
C

a.forEach(function (element, index, array)
 { 
console.log(index);
});
0 
1 
2

a.forEach(function (element, index, array)
 { 
console.log(array);
});
Array(3) [ "A", "B", "C" ]
Array(3) [ "A", "B", "C" ]
Array(3) [ "A", "B", "C" ]

Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身(element),同理这里的变量名也只是方便大家理解,可以修改

var s = new Set(['A', 'B', 'C']); 
 s.forEach(function (element, sameElement, set) { console.log(element); });

Map的回调函数参数依次为value、key和map本身,同理变量名只是方便理解

var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); 
 m.forEach(function (value, key, map) { console.log(value); });

如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们
只需要获得Array的element

var a = ['A', 'B', 'C']; 
a.forEach(function (element) { console.log(element); })

filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素
和map()类似,Array的filter()也接收一个函数,和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素

例如,在一个Array中,删掉偶数,只保留奇数

var arr = [1, 2, 4, 5, 6, 9, 10, 15]; 
 var r = arr.filter(function (x) { return x % 2 !== 0; });
 r;//Array(4) [ 1, 5, 9, 15 ]
 arr;//Array(8) [ 1, 2, 4, 5, 6, 9, 10, 15 ]

x&2!==0如果返回true说明是个奇数,如果是偶数则返回false
但注意了,arr不变

把Array中的空字符串删掉
先讲一下trim函数
trim用于去除字符串的头尾空格

var  str="    Noob  ";
str.trim();//"Noob"

由于javascript里面有几个先天就是false的常量
null,undefined,’’,"",0
所以有时候如果出现在了array里面我们可能想要去掉

var arr = ['A', '', 'B', null, undefined, 'C', ' ']; 
var r = arr.filter(function (s) { return s});
r;//Array(4) [ "A", "B", "C", " " ]第四个里面有空格,所以不是非空

另外上面出现的5个为false的,具体还是有一些差别的

""==false;//true
!null;//true
null==false;//false
!undefined;//true
undefined==false;//false
''==false;//true
0==false;//true

‘’,"",0直接就==false,但是null,undefined并不等于false,因为他们还有本身的意义,但是!后就等于true了,在一些返回值里面还是可以认为和false等价的,比如说像我们这里,根据返回值true和false进行取舍,盲猜实现的原理里面需要取个反,不然undefined和null还要出一点问题
这也提醒我们,之后如果判断null和undeifned的时候还是需要取反

但有时候,我们只想去掉全都是空格和空字符串,null和undefiend或许还有点用

var arr = ['A', '', 'B', null, undefined, 'C', ' ']; 
var r = arr.filter(function (s) { return String(s).trim();  });
r;//Array(5) [ "A", "B", null, undefined, "C" ]

注意啦,这里别用toString,因为null和undefined没有toString这个属性

String(null);//"null"
String(undefined);//"undefined"

filter()接收的回调函数,其实可以有多个参数
通常我们仅使用第一个参数,表示Array的某个元素
回调函数还可以接收另外两个参数,表示元素的位置和数组本身

var arr = ['A', 'B', 'C']; 
var r = arr.filter(function (element, index, self) { console.log(element); 
console.log(index); 
console.log(self); 
return true; }); 
A 
0 
Array(3) [ "A", "B", "C" ]
B 
1 
Array(3) [ "A", "B", "C" ]
C 
2 
Array(3) [ "A", "B", "C" ]

r
Array(3) [ "A", "B", "C" ]

按照每个元素的顺序依次执行,arr也被重复输出了3次
跟上面的ForEach有点像,不过后面要加上return,因为filter的本职工作

利用filter,去除Array的重复元素
indexOf()再上一节刚刚讲了,会搜索指定字符串或者字符出现的位置,返回第一个值

var arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry']; 
var r = arr.filter(function (element, index, self) { return self.indexOf(element) === index; }); 

r
Array(5) [ "apple", "strawberry", "banana", "pear", "orange" ]

这里的indexOf(element)只会返回第一个出现的索引,所以只有当元素是那个第一个出现的才会被留下,后面重复出现的都会被过滤掉