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)只会返回第一个出现的索引,所以只有当元素是那个第一个出现的才会被留下,后面重复出现的都会被过滤掉