日常开发中,数组或是对象的遍历是一个经常会遇到的事情,关于遍历,其实Js提供了很多方法,但是对于他们之间的区别却理解的不是很透彻,通常情况就是抓起来一个forEach就用。为了提高代码质量,我认为有必要深入了解一下不同遍历的特点。当然,本文不作太多深入讲解,只是就各种的特点进行整理展示。
for..in
,for..of
,forEach
for..in
:输出 索引let obj = {
a:1,
b:2,
c:3
}
for(let i in obj){
console.log(i)
}
//a
//b
//c
for..of
&& forEach
:不支持let arr = [1,'参数2',3]
for..in
:输出 索引for(let i in arr){
console.log(i)
}
//0
//1
//2
for..in
也可以通过 arr[i]
的方式输出值
for..of
:输出 值for(let i of arr){
console.log(i)
}
//1
//参数2
//3
forEach
:输出 值&索引arr.forEach((item,index)=>{
console.log(item,index)
}}
//1 0
//参数2 1
//3 2
let arr = [1,'参数2',3]
arr.attr='attr'
Array.prototype.arrCustom = function() {};
for..in
:全部输出for(let i in arr){
console.log(i)
}
//0
//1
//2
//attr
//arrCustom
当然也可以通过 hasOwnProperty
进行一些优化,但是自定义的属性依旧会输出
for(let i in arr){
if (arr.hasOwnProperty(i)) {
console.log(i);
}
}
//0
//1
//2
//attr
for..of
& forEach
:不受影响,输出正常let arr = [1,3,5,7,9]
for..in
:无法中断for..of
:可以使用break
中断for(let i of arr){
console.log(i);
if (i==5) {
break;
}
}
//1
//3
//5
forEach
:无法中断arr.forEach((item,i)=>{
console.log(item);
if (item==5) {
return false;
}
})
//1
//3
//5
//7
//9
for..of
特有的功能let str = 'mystr'
for(let i of str){
console.log(i);
}
//m
//y
//s
//t
//r
无需[].slice.call()
,也不需要Array.from()
进行数组转化
let typeArr = new Uint8Array([0x00, 0xff]);
for (let value of typeArr) {
console.log(value);
}
// 0
// 255
let mapData = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (let [key, value] of mapData) {
console.log(value);
}
// 1
// 2
// 3
let setData = new Set([1, 1, 2, 2, 3, 3]);
for (let value of setData) {
console.log(value);
}
// 1
// 2
// 3
等等。
for..of
是ES6中新增的语法,相对来说应用场景会更丰富一些,但是兼容性的话想对弱一些,使用的时候应酌情考虑
不考虑兼容性的情况下:
for..in
for..of
forEach
因为for..of
可以中断,所以数组遍历时更推荐使用。
除了以上三个重点列出的遍历方法外,其实JS中还有很多其他的遍历方法,只是应用场景稍有不同。
除了以上的for..in
,还有下面的一些方法也可以实现
var mySymbol = Symbol();
let myObj = {
name:'seven',
age:18,
[mySymbol]:'Hello!'//Symbol属性
}
Object.prototype.hobby = 'music';
myObj.sex='female'
Obeject.keys(obj)
可以返回一个数组,包括对象自身的所有可枚举属性,不包括继承的属性和Symbol属性
Object.keys(myObj)
//["name", "age", "sex"]
Object.getOwnPropertyNames(obj)
返回一个数组,包含对象自身的所有属性,不含Symbol属性,包括不可枚举属性
Object.getOwnPropertyNames(myObj)
//["name", "age", "sex"]
Object.getOwnPropertySymbols(obj)
返回一个数组,包含对象自身的所有Symbol属性
Object.getOwnPropertySymbols(myObj)
//[Symbol()]
Reflect.ownKeys(obj)
返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举
Reflect.ownKeys(myObj)
//["name", "age", "sex", Symbol()]
Array.every()
:测试数组的所有元素是否都通过了指定函数的测试
```
function isBelowThreshold(currentValue) {
return currentValue < 40;
}
var array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold)) // true
2. `Array.some()`:检测数组中的元素是否满足指定条件
+ 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
+ 如果没有满足条件的元素,则返回false。
> tip:不会改变原始数组
var ages = [3, 10, 18, 20];
function checkAdult(age) { return age >= 18; } ages.some(checkAdult) //true
3. `Array.filter()`:创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
> tip:不会改变原始数组
var ages = [32, 33, 16, 40];
function checkAdult(age) { return age >= 18; }
ages.filter(checkAdult) //[32, 33, 40]
4. `Array.map()`:返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组
> tip:不会改变原始数组
var ages = [32, 33, 16, 40];
function checkAdult(age) { return age + 1 }
ages.map(checkAdult) //[33, 34, 17, 41]
5. `Array.reduce()`:接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
> tip:不会改变原始数组
var numbers = [65, 44, 12, 4];
function getSum(total, num) { return total + num; } numbers.reduce(getSum); //125
numbers.reduce(getSum,2); //127 ```
本文关于for..in
、for..of
、forEach
的对比参考自张鑫旭大神的文章,传送门在这里:看,for..in和for..of在那里吵架!,文风还是挺诙谐幽默的,推荐一看!
07 Nov 2018