JavaScript数组遍历的十五种方法

数组方法:map

  • 核心

    • 创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
    • 不改变原数组
    • 返回值是一个新的数组
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子', '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];
    // 数组方法:map
    let mapFru= fruits.map(function(item, index, arr){
        item= `${item}啊!`;
        console.log(arr);
        return index+ ' - 爱吃'+ item;
    });
    console.log(mapFru);
    console.log('-------------------------');
    let mapVeg= vegetables.map(function(item, index, arr){
        // 返回 遍历子对象
        console.log(item);
        // 返回 遍历索引值
        console.log(index);
        // 返回 所有子对象
        console.log(arr);
    });

数组方法 forEach

  • 核心

    • 对数组的每个元素执行一次提供的函数。
    • 不改变原数组
    • 返回值总是undefined
    • map是forEach操作的具体化
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子', '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:forEach
    let forEachFru= fruits.forEach(function(item, index, arr){
        item= `${item}啊!`;
        // console.log(item);
        // console.log(index);
        // console.log(arr);
        return index+ ' - 爱吃'+ item;
    });
    console.log(forEachFru);
    console.log('-------------------------');
    let forEachVeg= vegetables.forEach(function(item, index, arr){
        // 返回 遍历子对象
        console.log(item);
        // 返回 遍历索引值
        console.log(index);
        // 返回 所有子对象
        console.log(arr);
    });
  • 手动封装一个forEach
   // 封装一个数组的 myForEach 方法 传参为一个函数
   function myForEach(fn){
        // 循环数组的每一项   谁调用的this就指向谁
        for(let i = 0; i < this.length; i++){
            // 循环传进来的函数的三个参数
            fn(this[i],i,this)
        }
    }
    // 定义一个数组
    let arr = ['4','5','6']
    // 将定义的这个数组方法放到Array的prototype下面
    Array.prototype.myForEach = myForEach;
    console.log(Array.prototype)
    // 数组arr调用myForEach方法并传参
    arr.myForEach(function(item,index,arr){
        // 打印传进来的参数
        console.log(item,index,arr)
    })

数组方法 filter

  • 核心

    • 对数组的每一项都进行过滤,返回符合条件的item组成的数组
    • 不改变原数组
    • 返回值是经过逻辑判断后,调用数组的一个子集
    • 没有任何的逻辑判断,可替代map或forEach使用,返回值为原数组
  • 优点:

    • 若是arr.filter(function(){return true}),则会跳过数组中缺少的元素,它的返回数组总是稠密的
    • 返回值为判断语句,则可方便筛选提取数组内的对象元素
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:filter
    let filterFru= fruits.filter(function(item, index, arr){
        item= `${item}啊!`;
        console.log(item);
        // console.log(index);
        // console.log(arr);
        return true;
    });
    console.log(filterFru);
    console.log('-------------------------');
    let filterVeg= vegetables.filter(function(item, index, arr){
        // 返回 遍历子对象
        // console.log(item);
        // // 返回 遍历索引值
        console.log(index);
        // // 返回 所有子对象
        // console.log(arr);
        return item.id== 2;
    });
    console.log(filterVeg);
  • 压缩空缺并删除undefinednull元素
arr= arr.filter(function(index){
    return index!== undefined && index!= null;
});

数组方法 find

  • 核心

    • 遍历数组,找到第一个符合条件的项,并返回该项。否则返回undefined
    • 不改变原数组
    • 返回值为true,则返回第一个元素
    • 当找到目标值后,停止遍历,并返回目标元素
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];
    // 数组方法:find
    let findFru= fruits.find(function(item, index, arr){
        item= `${item}啊!`;
        // console.log(item);
        // console.log(index);
        // console.log(arr);
        return index> 1;
    });
    console.log(findFru);
    console.log('-------------------------');
    let findVeg= vegetables.find(function(item, index, arr){
        // 返回 遍历子对象
        // console.log(item);
        // // 返回 遍历索引值
        console.log(index);
        // // 返回 所有子对象
        // console.log(arr);
        return item.id> 1;
    });
    console.log(findVeg);

数组方法 findIndex

  • 核心

    • 遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
    • 不改变原数组
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:findIndex
    let findIndexFru= fruits.findIndex(function(item, index, arr){
        // item= `${item}啊!`;
        // console.log(item);
        // console.log(index);
        // console.log(arr);
        return index> 5;
    });
    console.log(findIndexFru);
    console.log('-------------------------');
    let findIndexVeg= vegetables.findIndex(function(item, index, arr){
        // 返回 遍历子对象
        console.log(item.name);
        // // 返回 遍历索引值
        // console.log(index);
        // // 返回 所有子对象
        // console.log(arr);
        return item.id> 2;
    });
    console.log(findIndexVeg);

数组方法 indexOf

  • 核心

    • 从前往后遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
    • 不改变原数组
    • 字符串也有此方法,功能类似
  • 回调函数参数

    • 第一个参数:item 需要搜索的值
    • 第二个元素:index 数组中的的索引值,可以为负数,代表相对数组末尾的偏移量
    let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:indexOf
    let indexOfFru= fruits.indexOf('桃子');
    console.log(indexOfFru);

数组方法 lastIndexOf

  • 核心

    • 从后往前遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
    • 不改变原数组
    • 字符串也有此方法,功能类似
  • 回调函数参数

    • 第一个参数:item 需要搜索的值
    • 第二个元素:index 数组中的的索引值,可以为负数,代表相对数组末尾的偏移量
    let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:lastIndexOf
    let lastIndexOfFru= fruits.lastIndexOf('桃子');
    console.log(lastIndexOfFru);

数组方法 every

  • 核心

    • 对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。
    • 类似数学中的'针对所有',看数组的每个元素是否符合要求,都符合则返回true,否则返回false
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
    let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 数组方法:every
    let everyFru= fruits.every(function(item, index, arr){
        // item= `${item}啊!`;
        // console.log(item);
        // console.log(index);
        // console.log(arr);
        return index< 6;
    });
    console.log(everyFru);
    console.log('-------------------------');
    let everyVeg= vegetables.every(function(item, index, arr){
        // 返回 遍历子对象
        // console.log(item);
        // // 返回 遍历索引值
        console.log(index);
        // // 返回 所有子对象
        // console.log(arr);
        return item.id>= 0;
    });
    console.log(everyVeg);

数组方法 some

  • 核心

    • 是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true。
    • 类似数学中的'存在',看数组的每个元素是否符合要求,任一项返回true,否则返回true
  • 缺陷

    • 可以使用return,但是不能使用break和continue
  • 回调函数参数

    • 第一个参数:item 数组中的子元素
    • 第二个元素:index 数组元素的索引值
    • 第三个元素:arr 原数组
  • 关于return

    • return true; 遍历终止
    changeNum: function(val){
        // console.log(val);
        // 根据子组件传过来的数据,更新list中对应的数据
        this.list.some(function(item){
        if(item.id == val.id){
            item.num= val.num;
            // 终止遍历
            return true;
        }
        })
    }
    let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];
    // 数组方法:some
    let someFru= fruits.some(function(item, index, arr){
        // item= `${item}啊!`;
        // console.log(item);
        // console.log(index);
        // console.log(arr);
        return index< 6;
    });
    console.log(someFru);
    console.log('-------------------------');
    let someVeg= vegetables.some(function(item, index, arr){
        // 返回 遍历子对象
        // console.log(item);
        // // 返回 遍历索引值
        console.log(index);
        // // 返回 所有子对象
        // console.log(arr);
        return item.id>= 0;
    });
    console.log(someVeg);

数组方法 reduce

  • 核心

    • 接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
    • 第二个参数作为第一次调用的a的值
  • 缺陷

    • 可以使用return,但是不能使用break和continue
    let arrNum= [2, 4, 6, 8, 10];
    // 累加
    let sum= arrNum.reduce(function(x, y){
        return x+ y;
    }); 
    console.log(sum);

    // 累乘
    let multiple= arrNum.reduce(function(x, y){
        return x* y;
    }); 
    console.log(multiple);

    // 求最大值
    let bigger= arrNum.reduce(function(x, y){
        return x> y? x: y;
    }); 
    console.log(bigger);

数组方法 reduceRight

  • 核心

    • 接收一个函数作为累加器(accumulator),数组中的每个值(从右到左)开始缩减,最终为一个值。
    • 第二个参数作为第一次调用的a的值
  • 缺陷

    • 可以使用return,但是不能使用break和continue
    let arrNum= [2, 4, 6, 8, 10];
    // 累加
    let sum= arrNum.reduceRight(function(x, y){
        return x+ y;
    }); 
    console.log(sum);

    // 累乘
    let multiple= arrNum.reduceRight(function(x, y){
        return x* y;
    }); 
    console.log(multiple);

    // 求最大值
    let bigger= arrNum.reduceRight(function(x, y){
        return x> y? x: y;
    }); 
    console.log(bigger);

逻辑方法 for循环

  • 核心

    • 使用临时变量,并且遍历的是i.
  • 缺陷

    • 可以正常使用使用break和continue, 但是不能正常使用return
    let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 逻辑方法:for循环
    for(let i= 0; i<fruits.length; i++){
        console.log(fruits[i]);
    }

    console.log('-------------------------');
    
    for(let i= 0; i<vegetables.length; i++){
        console.log(vegetables[i].name);
    }

逻辑方法 for...in...循环

  • 核心

    • 使用临时变量,并且遍历的是key.
  • 缺陷

    • 可以正常使用使用break和continue, 但是不能正常使用return
    let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 逻辑方法:for...in...循环
    for(let key in fruits){
        console.log(fruits[key]);
    }

    console.log('-------------------------');
    
    for(let key in vegetables){
        console.log(key);
        console.log(vegetables[key].name);
    }

逻辑方法 for...of...循环

  • 核心

    • 使用临时变量,并且遍历的是value.
  • 缺陷

    • 可以正常使用使用break和continue, 但是不能正常使用return
    let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
    let vegetables= [{
        id: 1,
        name: '花椰菜'
    },{
        id: 2,
        name: '青椒'
    },{
        id: 3,
        name: '土豆'
    },{
        id: 4,
        name: '西红柿'
    }];

    // 逻辑方法:for...of...循环
    for(let value of fruits){
        console.log(value);
    }

    console.log('-------------------------');
    
    for(let value of vegetables){
        console.log(value);
        console.log(value.name);
    }

遍历器机制

  • 背景

    • 截止到ES6,JavaScript 已经拥有了数组、对象、Map集合和Set集合这样四种数据结构
    • 为了统一和简化遍历这四种数据结构的操作,ES6引入了遍历器机制。
  • 关于setmap

    var set = new Set();  
    set.add("a").add("b").add("d").add("c");  
    console.log(set);

    var map = new Map();  
    map.set("a",1).set("b",2).set(999,3);  
    console.log(map);

    for (let value of set) {  
        console.log(value);  
    }  
    console.log("--------------------");  
    for(let [key, value] of map) {  
        console.log(key, value);  
    }  
  • 基本概念
    • ES6 规定,可遍历的对象都具有Symbol.iterator 属性,这个属性指向一个函数,就是当前对象默认的遍历器生成函数。
    • 这个遍历器生成函数大致的模样可以用ES5 语法模拟出来:这个函数返回一个next() 方法,每调用next() 方法,都会返回数据结构的当前成员的信息。
    • 具体来说,就是返回一个包含value和done两个属性的对象。
    • 其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
// ES5 语法模拟遍历器
function createIterator(items) {
    let i = 0;
    return {
        next() {
            let done = i >= items.length;
            let value = !done ? items[i++] : undefined;
            return {
                done: done,
                value: value
            }
        }
    }
}

let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); 
//输出:{done: false, value: 1}
console.log(iterator.next()); 
//输出:{done: false, value: 2}
console.log(iterator.next()); 
//输出:{done: false, value: 3}
console.log(iterator.next()); 
//输出:{done: true, value:undefined }
  • 默认遍历器

    • 在ES6 中,已经默认为绝大多数內建的数据结构提供了遍历器,不需要像上面例子中那样自己去创建。
    • keys()方法:默认遍历器,其值为集合中的所有键名。
    • values()方法:默认遍历器,其值为集合中的所有值。
    • entries()方法:默认遍历器,其值为所有成员的键值对。
  • 注意:

    • 扩展运算符(…)会持续调用遍历器的next() 方法,并将value属性值插入到数组中,直到结果对象的done 属性值为true。
    • Set 集合的键名和键值是同一个值,所以keys() 方法和values() 方法的返回值完全一致。
const arr = ["A", "B", "C"];
console.log([...arr.keys()]); 
//输出:[0, 1, 2]
console.log([...arr.values()]); 
//输出:["A", "B", "C"]
console.log([...arr.entries()]); 
//输出:[[0, "A"],[1, "B"],[2, "C"]]

const set = new Set(arr);
console.log([...set.keys()]); 
//输出:["A", "B", "C"]
console.log([...set.values()]); 
//输出:["A", "B", "C"]
console.log([...set.entries()]); 
//输出:[["A", "A"],["B", "B"],["C", "C"]]

const map = new Map().set("name", "Tom").set("age", 19);
console.log([...map.keys()]); 
//输出:["name", "age"]
console.log([...map.values()]); 
//输出:["Tom", 19]
console.log([...map.entries()]); 
//输出:[["name", "Tom"],["age", 19]]
  • 不同数据结构的默认遍历器
    • 每个数据结构都有一个默认的遍历器,例如数组的默认遍历器是values()
      ,在没有明确指定遍历器的情况下,这些数据结构都会使用默认的遍历器。
    • 我们可以通过检测对象的Symbol.iterator 属性来判断对象是否拥有遍历器。
const arr = ["A", "B", "C"];
console.log(typeof arr[Symbol.iterator] === "function"); 
//输出:true
console.log(arr[Symbol.iterator]); 
//输出:function values() { ... }

const set = new Set(arr);
console.log(typeof set[Symbol.iterator] === "function"); 
//输出:true
console.log(set[Symbol.iterator]); 
//输出:function values() { ... }

const map = new Map().set("name", "Tom").set("age", 19);
console.log(typeof map[Symbol.iterator] === "function"); 
//输出:true
console.log(map[Symbol.iterator]); 
//输出:function entries() { ... }
  • 原生具备遍历器的对象
    • 数组、Map集合、Set集合、字符串、arguments和 NodeList(节点列表)。
    • 对象(Object)默认是不可遍历的
    • 我们可以通过Object.keys()、Object.values()和Object.entries() 方法把对象变成数组,使其拥有遍历器
    • 或者直接为对象添加Symbol.iterator 属性来自定义遍历器。
const obj = {
    name: "Tom",
    age: 19
}
console.log(typeof Object.entries(obj)[Symbol.iterator] === "function"); 
//输出:true
console.log([...Object.entries(obj)]); 
//输出:[["name", "Tom"],["age", 19]]
const obj = {
    name: "Tom",
    age: 19,
    [Symbol.iterator]() {
        let data = [],
            i = 0;
        for (let k in this) {
            if (this.hasOwnProperty(k)) {
                data.push(Array.of(k, this[k]));
            }
        }
        return {
            next() {
                let done = i >= data.length;
                let value = !done ? data[i++] : undefined;
                return {
                    done: done,
                    value: value
                }
            }
        }
    }
}
console.log([...obj]); 
//输出:[["name", "Tom"],["age", 19]]
  • 调用遍历器

    • 当我们去遍历拥有遍历器的对象的时候,系统就会自动去调用对象默认遍历器的接口。没有遍历器接口的对象不能被遍历。
  • for…of 循环

    • 我们知道,遍历器内部的next() 方法,每调用一次只会返回当前成员的信息
    • 而for…of循环将持续调用next() 方法直到返回对象的done 属性的值为 true。
const arr = ["A", "B", "C"];
const map = new Map().set("name", "Tom").set("age", 19);
const str = "love";

for (let v of arr) {
    console.log(v); 
    //输出:A B C
}

for (let [v, i] of map) {
    console.log(v + ":" + i); 
    //输出:name:Tom age:19
}

for (let v of str) {
    console.log(v); 
    //输出:l o v e
}
  • 展开运算符
    • 如果我们想把非数组可遍历对象的所有成员填充到一个数组中,最方便的方法是使用展开运算符(…)
    • 展开运算符会触发默认的遍历器取得所有的值,然后按照取得顺序依次插入到数组中。
console.log([...new Set([1, 2, 3])]) ;
//输出:[1, 2, 3]
console.log([1, ...new Set([2, 3]), ...
        "love";
    ]) 
//输出:[1, 2, 3, "l", "o", "v", "e"]
  • ES6中,由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器。例如Array.from()方法、Set()、Map()、解构赋值等等。
console.log(Array.from(new Set([1, 2, 3]))); 
//输出:[1, 2, 3]
let [a, b] = new Set([1, 2]);
console.log(a + "," + b); 
//输出:1,2
posted @ 2020-09-07 12:49  wing1377  阅读(752)  评论(0)    收藏  举报