JavaScript常用算法之——数组遍历的7种方法及兼容性处理

133 阅读2分钟
  • 原始for循环
    大家都会,不多说了
    let arr = [1, 2, 3];
    for (let i = 0; i < arr.length; i++) {
        console.log(arr[i]);
    }
  • forEach循环
    比较常用的数组循环,forEach接收一个回调参数,参数分别表示当前执行的元素值,当前值的索引和数组本身。在方法体中输出每个数组元素即可完成遍历。
    let arr = [1, 2, 3];
    arr.forEach (function(element, index, array) {
        console.log(element);
    }) 
    
    //由于低版本的浏览器不支持forEach,这里提供一个polyfill来实现
    
    Array.prototype.forEach = Array.prototype.forEach ||
        function (fn, context) {
            for (let k = 0; length = this.length; k < length; k++) {
                if (typeof fn === "function" &&
                    Object.prototype.hasOwnPrototype.call(this, k)) {
                    fn.call (context, this[k], k, this);
                }
            }
        }
        
    //通过for循环,在循环中判断this对象,即数组本身是否包含遍历的索引。如果包含则利用call()函数去调用回调函数,传入回调函数所需要的参数
  • map循环
    map函数不会改变原数组,在使用中更偏向于对每个元素进行处理后得到新的元素再返回由新元素所组成的数组,在需要一定处理的数组中非常好用
    let arr = [1, 2, 3];
    let sum5 = arr.map(function(element) {
        return element += 5; //return 是必须要的
    })
    console.log(sum5); // [6, 7, 8]
    
    //polyfill
    
    Array.prototype.map = Array.prototype.map ||
        function (fn, context) {
            let arr = []; //新数组
            if (typeof fn === "function") {
                for (let k = 0; length = this.length; k < length; k++) {
                    if (typeof fn === "function" &&
                        Object.prototype.hasOwnPrototype.call(this, k)) {
                        arr.push(fn.call (context, this[k], k, this));
                    }
                }
            }
            return arr;
        };
  • filter循环
    filter函数同样不会修改原数组,在使用中用于条件过滤留下满足条件的元素形成新的数组。也就是说新的数组是原数组的子集。
    let arr = [1, 2, 3];
    let result = arr.filter( num => {
        return num > 1;
    } )
    console.log(result); //[2, 3]
    
    //polyfill
    
    Array.prototype.filter = Array.prototype.filter ||
        function (fn, context) {
            let arr = []; //新数组
            if (typeof fn === "function") {
                for (let k = 0; length = this.length; k < length; k++) {
                    if (typeof fn === "function" &&
                        Object.prototype.hasOwnPrototype.call(this, k)) {
                        fn.call (context, this[k], k, this) && arr.push(this[k]);
                        //filter是判断返回值是否为true来决定是否将返回值push到新数组的,所以这里直接短路就可以了
                    }
                }
            }
            return arr;
        };
  • find循环
    find函数遍历寻找数组中符合条件的第一个参数,有满足条件的则直接返回满足条件的参数,没有满足条件则直接返回undefined。
    let arr = [1, 2, 3];
    let result = arr.find( num => {
        return num > 2;
    })
    console.log(result); //3
    
     //polyfill
    
    Array.prototype.find = Array.prototype.find ||
        function (fn, context) {
            if (typeof fn === "function") {
                for (let k = 0; length = this.length; k < length; k++) {
                    if (fn.call (context, this[k], k, this)) {
                        return this[k];
                    }
                }
            }
            return undefined;
        }
  • some循环&every循环
    some和every都是在循环过程中判断数组的参数是否满足条件,some只有有满足条件即返回true,否则返回false;而every必须所有参数都符合条件才会返回true,否则即返回false。
    let arr = [1, 2, 3];
    let resultSome = arr.some( sum => {
        return sum > 2;
    }) 
    let resultEvery = arr.every( sum => {
        return sum > 0;
    })
    console.log(resultSome, resultEvery); //true true
    
    //some polyfill
    Array.prototype.some = Array.prototype.some ||
        function (fn, context) {
            let flag = false; //结果标识
            if (typeof fn === "function" &&
                Object.prototype.hasOwnPrototype.call(this, k)) {
                for (let k = 0; length = this.length; k < length; k++) {
                    if (flag === true) break; //true则直接跳出循环
                    flag = !!fn.call(context, this[k], k, this);
                }
            }
            return flag;
        };
        
    //every polyfill
    Array.prototype.every = Array.prototype.every ||
        function (fn, context) {
            let flag = true; //结果标识
            if (typeof fn === "function" &&
                Object.prototype.hasOwnPrototype.call(this, k)) {
                for (let k = 0; length = this.length; k < length; k++) {
                    if (flag === false) break; //false则直接跳出循环
                    flag = !!fn.call(context, this[k], k, this);
                }
            }
            return flag;
        };
  • reduce循环
    reduce有很多非常强大的使用方法,这里我们来展示如何计算每个元素出现的次数
    let arr = [1, 2, 3, 1, 2, 1];
    let countOccurrences = function (arr) {
        return arr.reduce(function(accumulator, currentValue){
            accumulator[currentValue] ? accumulator[currentValue]++ : accumulator[currentValue] = 1;
            return accumulator;
        }, {});
    }
    countOccurrences(arr); //{ 1:3, 2:2, 3:1 };
    
     //reduce polyfill
    Array.prototype.reduce = Array.prototype.reduce ||
        function (callback, initialValue) {
            let previous = initialValue, k = 0, length = this.length;
            if (typeof initialValue === "undefined") {
                previous = this[0];
                k = 1;
            }
            if (typeof callback === "function") {
                for (k; k < length; k++) {
                    //每轮计算结束后,需要将计算结果重新赋值给第一个参数
                    this.hasOwnProperty(k) && (previous = callback(previous, this[k], k, this)); {
                    }
                }
            }
            return previous;
        };