首先for…in和for…of都是用来迭代一些东西,但是他们在迭代数据的时候有很大的不同
for…in
for…in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
// 数组
var arr = [10, 20, 30, 40, 50];
Array.prototype.myArray = function(){};
arr.youArray = 'youSome';
// 对象
var obj = {a: 10, b: 20, c: 30, d: 40};
Object.prototype.myObject = function(){}
obj.youObject = 'youObject';
for(let i in arr){
console.log(i);
}
// 上边代码输出结果:
// 0 1 2 3 4 youArray myArray myObject
可以看到for…in 遍历数组的缺点
- 把Array.prototype.myArray 数组对象原型上的方法和youArray都做了遍历输出;
- 因为数组也属于对象,也是由Object缔造出来的,所以也会把Object原型上的方法遍历出来。
在这种情况下我们如果使用for…in进行遍历就需要做一些判断
// 数组
var arr = [10, 20, 30, 40, 50];
Array.prototype.myArray = function(){};
arr.youArray = 'youSome';
for(let i in arr){
if(arr.hasOwnProperty(i)){
console.log(i);
}
}
// 上边的代码输出结果:
// 0 1 2 3 4 youArray
上边的代码中我们使用了hasOwnProperty方法进行当前项是否为自身属性而不是原型或者继承的属性。
通过上边代码示例可以看出for…in并不适合用来遍历数组,在遍历数组的时候最好的方法是使用数组自身提供的遍历方法如:forEach\map\filter\for…of等方法进行遍历。
for…of
for...of
语句主要用在原型上部署了Iterator迭代接口的数据类型上(包括 Array
,Map
,Set
,String
,TypedArray
,arguments
对象等等)可以循环遍历数据类型中的每一项调用自定义迭代钩子,并为每个不同属性的值执行语句
// 数组
var arr = [10, 20, 30, 40, 50];
Array.prototype.myArray = function(){};
arr.youArray = 'youSome';
for(let v of arr){
console.log(v);
}
//上边输出的结果是
// 10 20 30 40 50
可以看出for…of遍历的主要是值,同时它不会遍历出原型上的属性方法,和静态属性方法。
for…of循环不能用在对象上,因为对象没有部署Symbol.iterator迭代器所以没办法使用for…of进行遍历,我们可以给我们的对象增加迭代器来实现。
迭代器规则是:
- 迭代器需要时一个方法,并且返回一个对象;
- 对象中需要有next方法,表示每次进行迭代对象中的项目都调用该方法;
- 该方法也需要返回一个对象并且对象中有value、done项
// 定义一个对象
var myObject = {
a: 10,
b: 20,
c: 30,
d: 40,
list:[
10, 20, 30, 40
]
};
// 给对象增加迭代器,供for...of使用
myObject[Symbol.iterator] = function(){
// 定义一个变量用来存储迭代器的循环次数
let index = 0;
// 把当前的this存储下来
let that = this;
// 通过Object.values方法拿到对象中的所有值的数组集合
let value = Object.values(myObject);
// 返回一个对象
return {
// 定义迭代器每次执行的方法
next(){
// 如果当前循环没到最后一个
if(index < that.list.length){
// 继续循环
return {
value: that.list[index++],
done: false
}
}else{
// 如果循环完毕了,直接返回done=true表示循环完
return {
value: undefined,
done: true
}
}
}
}
}
for(let v of myObject){
console.log(v);
}
10 20 30 40 Array[10, 20, 30, 40]
通过上边的代码给对象增加迭代器,也能实现for…of的迭代对象,并且迭代器可以由我们自己来控制返回什么值。
通过上边的实例可以看出,for…in可以迭代任意类型,一般建议用在调试程序上,他能遍历出自身原型上自定义的属性和方法,也能遍历出继承的自定义属性和方法。
for…of是ES6新增的语法特性,主要是用来的带具有iterator接口的的类型,对象没有iterator接口所以不能使用for…of需要自己定义。