带你了解javascript常见的遍历方式

338 阅读5分钟

前言:对于js的循环遍历你了解多少呢?日常开发中常见几种JS数组(对象)遍历,基本就是for,forin,foreach,forof,map等等一些方法,以下介绍几种本文分析用到的数组(对象)遍历方式。

一.数组的遍历

1.for循环

var arr = ['a', 'b', 'c'];

for(var i = 0; i<arr.length; i++) {
    console.log(i, arr[i])
}
// 0 "a"
// 1 "b"
// 2 "c"

最简单的一种,也是使用频率最高的一种,虽然性能不弱.

2.for...of

for..of是ES6中引入的新特性,它主要的作用是:循环一个可迭代的对象。 它可以循环遍历,数组、字符串、Set对象等等

// 遍历字符串
var arr = 'Hello'
for (item of arr) {
    console.log(item) // 会依次打印H e l l o
}

// 遍历数组
 var arr = ['a', 'b', 'c']
for (item of arr) {
    console.log(item) // 会依次打印a b c
}

// 遍历对象
var obj = {
    x: 10,
    y: 20
}
for (objItem of obj) { 
    console.log(objItem)
 }
 // 这样会出现报错 obj is not iterable,意思是obj不是一个可迭代的对象,可以使用Object.keys将obj转化为数组,或者加迭代器,意思都差不多,易陷入死循环。
 obj[Symbol.iterator] = () => {
    let keys = Object.keys(obj) //获取对象的key值
    let len = keys.length
    let n = 0
    return {
        next() {
            if (n < len) { //继续循环
                return {
                    one: false,
                    alue: obj[keys[n++]] // 每次循环返回的值
                }
            } else { // 跳出循环
                return {
                    done: true
                }
            }
        }
    }
}
for (objItem of obj) {
    console.log(objItem) // 依次打印 10  20
}

// 遍历set对象
Set对象是ES6中新增的类型,可以自动排除重复项,生成Set对象后,可以轻松遍历它所包含的内容。
var str = new Set("Hello world!");
for (var item of str) {
    console.log(item + " ")
}
// 结果会是这样:H e l o w r d! 已经是去重复的数据了
    

3.for...in

声明用于对数组或者对象的属性进行循环/迭代操作

遍历Object多些,效率低于for, for...of

// 遍历数组
var arr = ['a', 'b', 'c']
for (var i in arr) {
    console.log(arr[i])  // a b c
}

// 遍历对象
 var obj = {
    a: '1',
    b: '2'
}
 for (var i in obj) {
    console.log(i, obj[i]) // i是键,obj[i]是值
}
// a 1
// b 2

4.forEach

var arr = [4, 3, 2, 1];
arr.forEach(function (val, index, arr) {
    console.log(val);  //当前数组中元素
    console.log(index); //索引。
    console.log(arr);   //当前数组
});

5.map

forEach和map循环的区别:forEach没有返回值,即使你给出return也不管用,map会返回一个新数组给你,原数组不会发生改变。

var arr = [1, 2, 3];
var newNum = arr.map((item, index) => {
    return item + 1
})
console.log(arr, newNum);
// [1,2,3] [2,3,4]

6.filter()

filter()方法会创建一个新数组,原数组的每个元素传入回调函数中,回调函数中有return返回值,若返回值为true,这个元素保存到新数组中;若返回值为false,则该元素不保存到新数组中;原数组不发生改变。

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次打印'A', 'B', 'C'
    console.log(index); // 依次打印0, 1, 2
    console.log(self); // self就是变量arr
    return true;
});

7.some()

some不会对空数组进行检测,不会改变原始数组。
语法:
arr.some(callback(item,index,data){})

var a = [11, 50, 40, 3, 5, 80, 90, 4];
a.some((item, index, array) => {
    console.log(item,index); // item数组的每一项,index为索引
    console.log(array) //返回的数组
})

8.some()

some()是对数组中每一项运行给定函数,如果该函数满足任一项返回true,则返回true
var a=[1,2,4,69,56,89]
var some1=a.some((item)=>{
    return item > 88
})
 console.log(some1)//true

二.对象object的遍历

1.for...in

上面已经提到就不多说了.

2.自身可枚举属性

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致,Object.keys()只返回自己的属性键;

   let obj1 = {
       A: 'a',
       B: 'b'
   };
   let obj2 = {
       C: 'c',
       D: 'd'
   };
   Object.setPrototypeOf(obj2, obj1);
   Object.keys(obj2); // => ['C', 'D']
       
   obj2['A'];  // => 'a'
   obj2['B'];    // => 'b'

Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。 Object.keys(obj2)返回obj2对象的自身可枚举属性键:['C','D']。

for..in语句的区别,for..in不仅可以循环枚举自身属性还可以枚举原型链中的属性

3.Object.values() 返回属性值

Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组.

let meals = {
   A: 'a',
   B: 'b',
   C: 'c'
};
for (let key of Object.values(meals)) {
   console.log(key);
}
//a
//b
//c

4.Object.entries()

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致

let meals = {
    A: 'a',
    B: 'b',
    C: 'c'
};
for (let [key, value] of Object.entries(meals)) {
    console.log(key + ':' + value);
}
// A a
// B b
// C c

Object.entries()返回一个与数组解构赋值兼容的集合,因此不需要为赋值或声明添加额外的行。

当普通对象要转换成 Map 时Object.entries() 就很有用,因为Object.entries() 返回的格式与Map构造函数接受的格式完全相同

let meals = {
    A: 'a',
    B: 'b',
    C: 'c'
};
let dataMap = new Map(Object.entries(meals));
dataMap.get('A'); // => 'a'
dataMap.get('B');  // => 'b'
dataMap.get('C'); // => 'c'

Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值

Map提供了与Object.values()和Object.entries() 等效的方法(只是它们返回Iterators),以便为Map实例提取属性值或键值对:

Map.prototype.values() 等价于Object.values()

Map.prototype.entries() 等价于Object.entries()

let meals = {
    A: 'a',
    B: 'b',
    C: 'c'
};
let dataMap = new Map(Object.entries(meals));

[...dataMap.values()]; // => ['a', 'b', 'c']

[...dataMap.entries()];
// => [ ['A', 'a'], ['B', 'b'],['C', 'c'] ]

返回迭代器对象,要将结果放入数组,需加扩展运算符…。

结语:

总结的不够完善,才疏学浅,往大佬多多吐槽。