遍历数组

for循环

遍历数组常用for循环 ES5遍历数组的方法有forEach,map,filter,some,every,reduce等
使用forEach不能使用break和return跳出循环

es5的forEach方法其实性能比for循环还要弱,使用for循环可以将长度用遍历存起来,可以优化性能

Array.prototype.method = function () {
console.log(this.length);
};
var myArray = ["a", "b", "c", "d"];
myArray.name = "数组";

for(let j = 0,len = myArray.length; j < len; j++){
console.log(myArray[j]);
}
for…in

使用for in 遍历数组的毛病

1.index是字符串
2.遍历顺序可能不是数组的内部顺序
3.会遍历数组的可枚举对象包括原型,例如上面的method和name
所以for in 不适合遍历数组

for(let index in myArray) {
console.log(index,myArray[index])
// 0 a
// 1 b
// 2 c
// 3 d
// name 数组
// method function() {
// console.log(this.length)
// }
}
for…of

使用for of 遍历的是数组的值而 for in 遍历的是数组的键名
for of遍历只会遍历数组自身的值,而不会去遍历原型和其他属性

for(let val of myArray) {
console.log(val)
}

遍历对象

1.使用for in遍历对象
Object.prototype.method = function () {
console.log(this);
};
const myObj = {
a: "apple",
b: "banane",
c: "cherry",
};
for(let i in myObj) {
console.log(i,myObj[i])
// 会遍历到原型上的方法和属性
// a apple
// b banane
// c cherry
// method function() {
// console.log(this)
// }
}

如果不想遍历原型上的方法和属性可以使用hasOwnPropery
hasOwnPropery可以判断某属性是否是对象的实例属性,从而过滤掉原型上的属性

for(let i in myObj) {
if(myObj.hasOwnProperty(i)) {
console.log(i, myObj[i])
}
// 只获取自身属性
// a apple
// b banane
// c cherry
}
for…of

也可以使用for of 搭配Object.keys 来遍历对象 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性).
相关的Object属性还有
Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性).
使用Reflect.ownKeys(obj)遍历 返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举.

for(let key of Object.keys(myObj)) {
console.log(key, myObj[key])
// 不包含原型属性
// a apple
// b banane
// c cherry
}

如果实在想用 for of遍历对象,可以给该对象添加Symbol.iterator迭代器接口
接口自己实现
for of循环会先调用集合的Symbol.iterator方法,然后返回一个新的迭代器对象,
迭代器对象可以是任意具有next方法的对象,迭代器对象会重复调用这个方法
每循环一次调用一次
迭代器对象可以是任意具有next方法的对象,迭代器对象会重复调用这个方法var
使用Genertaor 自带next()

myObj[Symbol.iterator] = function* () {
yield this.a;
yield this.b;
yield this.c;
};
// 实现一个简单的迭代器
myObj[Symbol.iterator] = function() {
const self = this;
const keys = Object.keys(self);
const len = keys.length;
let pointer = 0;
return {
next() {
const done = pointer >= len;
const value = !done ? self[keys[pointer++]]: undefined;
return {
done,
value
}
}
}
}
for (let item of myObj) {
console.log(item);
}

使用for of 遍历Map对象 顺便回顾一下Map对象的基本使用

const myMap = new Map([
["a", "apple"],
["b", "banane"],
["c", "cherry"],
]);
// 给Map对象添加属性
console.log(myMap.set('d', 'durian')) // 返回是添加之后的Map
// 判断key是否存在 返回值 是否存在
myMap.has('a') // true
console.log('myMap.has(\'a\'): ', myMap.has('a'));
// myMap.delete('a') // 删除属性 返回值 是否删除成功
console.log('myMap.delete(\'a\'): ', myMap.delete('a'));
// myMap.get('d') // 获取属性
console.log('myMap.get(\'d\') : ', myMap.get('d') );
使用数组结构 Map的item
for(let [key, val] of myMap) {
console.log(key, val)
}

小结

for of 使用于遍历数组/数组对象[{},{}]/字符串/map/set等有迭代器对象的集合
但不能遍历对象,应为对象没有迭代器对象,它可以正确的相应break、continue、return语句
es5的forEach方法其实性能比for循环还要弱,使用for循环可以将长度用遍历存起来,可以优化性能

参考链接

for in 和for of的区别
ES6可迭代对象与迭代器的理解