我们知道遍历数组的方式之一就是 使用for循环、while循环或do…while循环来遍历,如:
var arr = [1, 2, 3, 4, 5];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]); //1,2,3,4,5
}
ES5发布之后,可以使用 数组的forEach() 迭代方法来遍历数组:
var arr = [1, 2, 3, 4, 5];
arr.forEach(function (value) {
console.log(value); //1,2,3,4,5
});
但有一个小小的缺陷:就是不能使用break、continue语句等来中断函数,也不能使用return语句返回到外层函数。
还可以使用 for-in枚举方法 来遍历数组
var arr = [1, 2, 3, 4, 5];
for (var i in arr) {
console.log(i); //返回的是索引 0,1,2,3,4
console.log(arr[i]); //返回的是数组项的值 1,2,3,4,5
console.log(typeof(i)); //返回的是 string,string,string,string,string,string 字符串
- for-in除了可以遍历数组外,还可以遍历自定义属性,也就是可以枚举可枚举属性。可是在遍历数组时,它还额外执行一次,用于遍历可枚举属性,但是这是我们不需要的操作。甚至还会遍历到数组原型链上的属性,这更是一个大麻烦。
- for-in循环还有一个更大的缺点:那就是它会以随机次序遍历数组元素,这更是我们不想要的。也就是说它遍历出的元素的顺序不是数组中真正的顺序。
for-in 用于遍历字符串类型的键
for-of 用于遍历字符串类型的值
for-of循环
在ES6中,有一个新的特性for-of循环可以用来遍历数组:
var arr = [1, 2, 3, 4, 5];
for (var i of arr) {
console.log(i); //1,2,3,4,5
for-of循环的优点:
- 更为简单更为直接的能遍历数组
- 避开了for-in循环的所有缺点
- 与forEach()不同的是,for-of循环可以使用break、continue、return等语句来中断函数的运行。
- for-in循环主要用于对象属性的遍历。
- for-of循环用于遍历数据–如对数组元素的遍历
for -of对其它集合的遍历
for-of循环不仅用于数组,还可以用于数组对象等,如DOM中的nodeList等,可以用来遍历DOM中的子节点、根据给定条件返回的元素节点的集合等。
for-of循环还可以用于遍历字符串
var str = "hello ES6";
for (var i of str) {
console.log(i); //h e l l o E S 6
}
for-of循环还支持对Map和Set对象的遍历
Array
定义: 有序并且可以重复的集合
Array.xxx:
- Array.isArray() 判断某一个变量是否为一个数组 【es5】
- Array.from() 【es6】
- Array.of() 【es6】
Array.prototype.xxx
- find()
- findIndex() 返回值的是匹配元素的索引
- includes()
- keys() 返回值是遍历数组索引的迭代器
- values() 返回数组元素的迭代器
- entries() 返回遍历数组中key-val的entry的迭代器
Set
定义: 无序不可以重复的集合
实例化
- new Set()
- new Set(可迭代的对象)
//会遍历并且自动去重
- Array.from(new Set(“hello”))
- Array.from(new Set(“hello”)).join()
- Array.from(new Set(“hello”)).join("")
- […new Set(“hello”)]
迭代器Iterator
Iterator 是 ES6 引入的一种新的遍历机制,迭代器有两个核心概念
- 迭代器是一个统一的接口,它的作用是使各种数据结构可被便捷的访问,它是通过一个键为Symbol.iterator 的方法来实现。
- 迭代器是用于遍历数据结构元素的指针(如数据库中的游标)。
迭代过程
迭代的过程如下:
- 通过 Symbol.iterator 创建一个迭代器,指向当前数据结构的起始位置
- 随后通过 next 方法进行向下迭代指向下一个位置, next 方法会返回当前位置的对象,对象包含了 value 和 done 两个属性, value 是当前属性的值, done 用于判断是否遍历结束
- 当 done 为 true 时则遍历结束
上面的例子,首先创建一个数组arr,然后通过 Array.iterator 方法创建一个迭代器,之后不断的调用 next 方法对数组内部项进行访问,当属性 done 为 true 时访问结束。
迭代器是协议(使用它们的规则)的一部分,用于迭代。该协议的一个关键特性就是它是顺序的:迭代器一次返回一个值。这意味着如果可迭代数据结构是非线性的(例如树),迭代将会使其线性化。
可迭代的数据结构
以下是可迭代的值:
- Array
- String
- Map
- Set
- Dom元素(正在进行中)
Array
引: 数组的创建方式
new Array(3,2)
[…string]
- Array.from(v)
注意: v为类数组对象或者可遍历的对象
let array_like = {"0":"terry","1":"larry",length:2}
console.log(array_like);
// 从数组对象中解构出来slice方法 let {slice} = [];
//1. 使用原始的Array.prototype.slice转换console.log(slice.call(array_like,0));
//2. 使用Array.from转换
console.log(array_like);
console.log(Array.from(array_like));//3. 使用Array.from转换可以遍历的对象
let set = new Set([1,2,3,1,2,4,5,6]);
console.log(set);
console.log(Array.from(set));
- Array.of(p1,p2,…)
- Array.prototype.includes
- Array.prototype.find
- Array.prototype.findIndex
let arr = [
{name:"terry",age:12},
{name:"tom",age:14},
{name:"larry",age:13},
{name:"jacky",age:18},
{name:"vicky",age:11}
]
//let result = arr.find(item=>item.age === 13)
let result = arr.find(function(item){
return item.age === 13
})
console.log(result);
- Array.prototype.fill
new Array(3).fill(9)
- Array.prototype.keys 对键的遍历
- Array.prototype.values 对值的遍历
- Array.prototype.entries 对键值对的遍历
数组的迭代
let arr = ["terry","larry","tom","jacky"];
//1. 获取迭代器
let values_iterator = arr.values();
//2. 通过迭代器获取数组中的元素
let item ;
while(!(item = values_iterator.next()).done){
console.log(item.value);
}
//3. 使用for-of遍历迭代器let entry_iterator = arr.entries();
for(let entry of entry_iterator){
console.log(entry);
}
//4. 使用for-of遍历数组
for(let item of arr){
console.log(item);
}
string
字符串是可迭代的,单他们遍历的是 Unicode 码,每个码可能包含一个到两个的 Javascript 字符。
for (const c of 'z\uD83D\uDC0A') {
console.log(c);
}
// output:
// z
// \uD83D\uDC0A
Set
定义: 无序不可以重复的集合(数组中的元素可以重复),Set 本身是一个构造函数,用来生成 Set 数据结构。
特点: Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
[…new Set(array)] // 去除数组的重复成员
- 实例化Set对象
let set = new Set();
let set = new Set([1,2,3,1,2])
- Set.prototype.xxx
size 返回Set实例的成员总数
add(val) 添加某个值,返回Set结构本身
delete(val) 删除某个值,返回一个布尔值,表示删除是否成功
has(val) 返回一个布尔值,表示该值是否为Set的成员
clear() 清除所有成员,没有返回值
forEach() 使用回调函数遍历每个成员
keys() 返回键名的遍历器
values() 返回键值的遍历器
entries() 返回键值对的遍历器
const set = new Set();
set.add("zero");
set.add("one");
for (let item of set) {
console.log(item);
}
// output:
// zero
// one
Map
key可以为任意数据对象(对象的key只能为字符串)
- 实例化map对象
let map = new Map();
let map = new Map(entry);
- Map.prototype.xxx
size
set(key,val) 向map中添加键值对,key不可以重复,如果重复,value更新
get(key) 通过key获取value
has(key) 判断map集合中是否存在指定的key
delete(key) 通过key从map集合中删除
clear() 清空map集合
keys() 迭代器对象
values() 迭代器对象
entries() 迭代器对象
const map = new Map();
map.set(0, "zero");
map.set(1, "one");
for (let item of map) {
console.log(item);
}
// output:
// [0, "zero"]
// [1, "one"]
类数组对象到数组的转换
Array.prototype.slice.call(arrayLike,0)
arguments
arguments 目前在 ES6 中使用越来越少,但也是可遍历的
function args() {
for (let item of arguments) {
console.log(item);
}
}
args("zero", "one");
// output:
// zero
// one
普通对象不可迭代
原因: 普通对象是由 object 创建的,不可迭代
// TypeError
for (let item of {}) {
console.log(item);
}
总结:
- 未来JavaScript还有许多的新的集合类型出现,那么for-of循环就是用来遍历这些新的集合类型的。
- for-of循环不支持对普通对象的遍历,for-of循环语句通过方法调用来遍历各种集合。
- 如果想遍历普通对象,可以使用for-in循环,for-in循环主要是遍历对象的属性的(键/值)。
- 数组、Map、Set对象以及其它对象有一个共同点:它们都有一个迭代器方法。
- 可以为任何类型的对象添加迭代器方法。
当我们向任意对象添加 Symbol.iterator 方法后,就可以遍历这个对象了。 - Symbol是ES6中的一个新特性,所有拥有Symbol.iterator方法的对象被称为可迭代的。