web开发知识总结(1)--数组方法详解(很详细)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011350550/article/details/81283850

web开发知识总结(1)–数组方法详解

web开发知识总结是一个系列的文章,本人将会总结项目开发过程中比较常用的技能及知识,每个知识点会作为一篇文章呈现出来,力争讲解通俗易懂、深入浅出。数组方法详解就作为这个系列的第一篇。
若果想和作者交流,请发信息至[email protected]

javascript数组在开发中十分常用,其方法也很多,很多同学开始学习JavaScript时,对数组方法都会有些迷惑,今天就带大家一起学习一下JavaScript数组及方法。同时会用一些常用例子来验证方法功能。
数组是一系值的有序集合,而且是无类型的,即一个数组中可能既有整数,也有对象和字数串等等。JavaScript中数组是动态的,例如:var arr = new Array(5); arr[6] = 1;这种代码是可以正常运行的,当然我们推荐这么做。JavaScript中数组也可能是稀疏的,arr[10]存在,arr[9]可能不存在。这与c/c++及java中的数组区别很大,一定要注意,不然很容易迷糊。
先看看数组主要有哪些方法,concat , every,fill,filter,find,findIndex,forEach, indexOf,join,map, pop,push,shift,unshift,reduce,reduceRight,reverse,slice,some,sort,values,toString,看到这么多,晕了吧。下面就开始介绍数组的方法功能。
数组方法分为两类:
- 不改变原数组的

  • 改变原数组的

下面会从数组应用的几个方面进行讲解,包括数组初始化,取子数组,过滤查找,排序,堆栈,遍历的多个方面讲解上述方法的使用

1、数组初始化(涉及方法,Array(),fill)

初始化一般有两种形式,使用[]或 new Array();

 let initArray0 = [];//定义一个空数组
 let initArray1 = [10,5,19,15,13];//length为5,并且初始化。

 let initArray2 = new Array();//等价于[]
 let initArray3 = new Array(5);//定义一个length为5的数组

举例,现在有一个需求,有这么一个函数function init(n, m){},n是数组长度,m数组的填充值,要求返回一个长度为n,所有值为m的数组。这很简单对不对。如下:

 function init(n, m) {
     //参数判断检查
     if (typeof n === 'undefined' || typeof m === 'undefined') {
         throw new Error('n or m is undefined');
     }
     if  (!/^\d+$/.test(n)) {
        throw new Error('n is not a positive number');
     }
     let len = Number(n);
     let arr = [];
     for (let i = 0; i < len; i++) {
         arr.push(m);
     }
     return arr;
 }

写JavaScript一定要多做参数检查,不能图省事,很多bug可能都是由于没检查参数有效性引起的。
现在增加一个要求,函数内部不使用循环,如何做呢?array有一个函数fill,先看下其接口描述。

fill(value: T, start?: number, end?: number)

fill有三个参数,value是填充进数组的值,start是起始位置,end是结束位置的下一个,省略start和end默认填充所有位置。
注意:该函数改变原数组。
所以,修改后的函数如下:

function init2(n, m) {
    //参数判断检查
    if (typeof n === 'undefined' || typeof m === 'undefined') {
        throw new Error('n or m is undefined');
    }
    if  (!/^\d+$/.test(n)) {
       throw new Error('n is not a positive number');
    }
    let len = Number(n);
    let arr = new Array(len).fill(m);
    return arr;
}

2、取子数组(涉及方法,slice)

数组的取子数组可以用循环,但是array有个自带的函数slice,很好用,函数介绍如下:

slice(start?: number, end?: number);

start是起始位置,end是结束位置的下一个。
该函数返回要取得子数组。
注意:该函数不修改原数组。

let arr = [1,3,2,3,5];
console.log(arr.slice(2, 4)); //输出为[2, 3]
console.log(arr); //输出为[1, 3, 2, 3, 5]

3、过滤查找(涉及方法:find,findIndex,indexOf,lastIndexOf,filter)

find主要用于数组查找某个元素,findIndex则用于查找某个元素对应的index

find(func(value,index,obj){})
findIndex(func(value,index,obj){})

find的参数是一个函数,第一个参数是value,第二个是value对应索引(index),第三个参数就是数组本身了。返回值是使函数func第一返回true的值,若都不满足,则反水undefined。findIndex与find类似,返回值有区别,是返回value对应index,若都不满足,则返回-1。举个例子:

let arr = [13, 24, 9, 5];
//查找小于num的数字
function findLessNumber(num) {
    let target = arr.find((value, index, obj) => {
        return value < num;
    });
    return target;
}
//查找小于num的数字对应的索引(index)
function findLessIndex(num) {
    let target = arr.findIndex((value, index, obj) => {
        return value < num;
    });
    return target;
}
console.log(findLessNumber(10)); //9
console.log(findLessNumber(0)); //undefined
console.log(findLessIndex(10)); // 2
console.log(findLessIndex(0)); //-1

根据输出,可以看出,find和findIndex是从前向后遍历数组,并返回第一个满足条件的值或索引。
indexOf 常用与查找数组内是否存在某个值,如果存在,就返回它的索引,如果存在多个,就返回最前面一个满足条件值的索引。lastIndexOf 则是返回最后一个满足条件值的索引。若没有满足条件的值,则返回-1.用法如下:


console.log([1,3,10,3,9,12,3].indexOf(3));//1
console.log([1,'3',10,3,9,12,3].indexOf(3));//3

console.log([1,3,10,3,9,12,3].lastIndexOf(3));//6
console.log([1,3,10,3,9,12,3].indexOf(0));//-1
console.log([1,3,10,3,9,12,3].lastIndexOf(0));//-1

注意:indexof和lastIndexOf是使用 === ,而不是 ==。由前两个例子可以看出区别。

filter 是array中非常常用的一个方法,作用是用数组中满足条件的值组成新数组,然后返回。若无满足条件的值,则返回空数组[]。

let studentList = [{
    name: 'xxx',
    age: 16
},
{
    name: 'aaa',
    age: 19
},
{
    name: 'bbb',
    age: 13
},
{
    name: 'ccc',
    age: 17
}]
function ageLessNum(num) {
    //filter三个参数,item是值,index是对应索引,obj是数组本身。
    let list = studentList.filter(function(item,index,obj) {
        return item.age < num;
    });
    return list;
}
//查找年龄小于 18 的学生
console.log(ageLessNum(18));
/* 
输出如下:
[{
    name: 'xxx',
    age: 16
},
{
    name: 'bbb',
    age: 13
},
{
    name: 'ccc',
    age: 17
}]*/
//查找年龄小于10的学生,返回为空[]
console.log(ageLessNum(10)); // []

注意:以上几个方法都不会修改元素组。

4、数组排序(涉及方法:sort)

这又是常用的功能之一,页面上经常会展现一些列表,列表数据肯定要按一定的顺序来展示可能按时间,或者按名称等等。这就会使用到sort方法。看下几个例子:

let arr = [12,9,18,3,44,55];
//val1和val2是数组中任意的两个值,返回true则会调换位置,返回FALSE则不改变位置。
//这个实现的是升虚排列。
arr.sort((val1, val2) => {
    return val1 > val2;
});
console.log(arr);// [3, 9, 12, 18, 44, 55]

实际应用中,数组中的值一般是对象,而我们是根据对象的某个属性来进行排序。下面实现一个一般性的函数,大家可以直接拿过去用。如下:

/**
 * 函数有三个参数,第一个arr是数组,第二个prop是排序属性,第三个flag是升降序标志位
 */

function sortArr(arr, prop, flag = 'desc') {
    //参数检查
    if (!Array.isArray(arr)) {
        throw new Error('arr is illegal');
    }
    if (!prop || typeof prop !== 'string') {
        throw new Error('prop is illegal');
    }
    if (arr.length === 0) {
        return;
    }
    //判断属性是字符串,还是数组
    if (typeof arr[0][prop] === 'number') {
        if (flag === 'desc') {
            arr.sort(function(val1, val2) {
                return val1[prop] < val2[prop];
            });
        } else {
            arr.sort(function(val1, val2) {
                return val1[prop] > val2[prop];
            });
        }
    } else {
        if (flag === 'desc') {
            arr.sort(function(val1, val2) {
                return !val1[prop].localeCompare(val2[prop]);
            });
        } else {
            arr.sort(function(val1, val2) {
                return val1[prop].localeCompare(val2[prop]);;
            });
        }
    }
}
let studentList = [{
    name: 'xxx',
    age: 16
},
{
    name: 'aaa',
    age: 19
},
{
    name: 'bbb',
    age: 13
},
{
    name: 'ccc',
    age: 17
}]
sortArr(studentList, 'name', 'desc');//按姓名降序排
sortArr(studentList, 'name', 'asc');//按姓名升序排
sortArr(studentList, 'age', 'desc');//按年龄降序排
sortArr(studentList, 'age', 'asc');//按年龄升序排

上述程序是正确的,大家可以验证下,我就不列出排序结果了。
注意:sort会修改原素组

5、堆栈操作(涉及方法: pop,push,shift,unshift,splice)

这一节,将实现一个双向队列,除基本功能外,还具有查找、替换、删除,按条件增加等等功能。
先介绍下几个方法的功能。pop是队尾出栈,push队尾入栈。shift队首入栈,unshift是队首出栈。splice功能如下:

/**
 * splice(start, deleteCount, ...items)
 * start是开始删除的index,deleteCount是删除的个数,...item是要从start开始插入的值
 */

let arr = [2,3,5,1,10,6];
//index从2开始,删除1个,即删除5
arr.splice(2,1);
console.log(arr);//[2, 3, 1, 10, 6]
//从3开始删除2个(10和6),插入3,3,3
arr.splice(3,2,3,3,3);
console.log(arr);//[2, 3, 1, 3, 3, 3]

基本方法已经了解,那我们是来实现消息队列,代码如下,代码中已有注释,就不再讲解代码。

/**
 * 利用闭包创建一个单例模式
 */
let Queue = (function(){
    let instance = null;

    //队列的构造函数
    function createQueue() {
        //队列数组
        this.queue = [];
    }

    //队列原型
    createQueue.prototype = {
        constructor: createQueue,
        //队尾入栈
        push: function(item){
            if (typeof item === 'undefined' || item === null) {
                throw new Error('the parametr of push is illagel');
            }
            this.queue.push(item);
        },
        //队首入栈
        unshift: function(item) {
            if (typeof item === 'undefined' || item === null) {
                throw new Error('the parametr of push is illagel');
            }
            this.queue.unshift(item);
        },
        //队尾出栈
        pop: function() {
            if (this.queue.length > 0) {
                return this.queue.pop();
            } else {
                return null;
            }
        },
        //队首入栈
        shift: function() {
            if (this.queue.length > 0) {
                return this.queue.unshift();
            } else {
                return null;
            }
        },
        //按位置插入值
        insert: function(num, value) {
            if (typeof num !== 'number' || typeof value === 'undefined' || value === null) {
                throw new Error('the parametr of insert is illagel');
            }

            if (num < this.queue.length) {
                this.queue.splice(num, 0, value);
            } else {
                throw new Error('the parametr of insert is illagel');
            }
        },
        //删除制定位置
        delete: function(num) {
            if (typeof num !== 'number') {
                throw new Error('the parametr of delete is illagel');
            }

            if (num < this.queue.length) {
                this.queue.splice(num, 1);
            } else {
                throw new Error('the parametr of insert is illagel');
            }

        },
        //查询值的索引
        query: function(value) {
            return this.queue.indexOf(value);
        },
        //获取制定位置的值
        get: function(index) {
            if (index < queue.length) {
                return this.queue[index];
            } else {
                throw new Error('the parametr of insert is illagel');
            }
        },
        getAll: function() {
            return this.queue;
        }
    }

    //队列代理函数
    return function() {
        if (instance === null) {
            instance = new createQueue();
        } 
        return instance;
    }
})();

let arr = new Queue();
arr.push(1);//[1]
arr.push(7);//[1,7]
arr.push(3);//[1,7,3]
arr.unshift(10);//[1,7,3,10]
arr.insert(3,6);//[10, 1, 7, 6, 3]
arr.delete(2);//[10, 1, 6, 3]

注意:这些方法都是修改原数组的

5、数组的遍历(涉及方法:forEach, map, reduce,reduceRight, some, every)

第一类方法: for 循环,例子如下:

let arr = [9,10,3,4,2];
for(index in arr) {
    console.log(arr[index]);
}
for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

第二类方法:forEach,map

let arr = [9,10,3,4,2];
let arr1 = arr.forEach(function(value, index, obj){
    value = value*2;
});
console.log(arr);//[9, 10, 3, 4, 2]
console.log(arr1);//undefined

let arr2 = arr.map(function(value, index, obj){
    value = value*2;
    return value;
});
console.log(arr);//[9, 10, 3, 4, 2]
console.log(arr2);//[18, 20, 6, 8, 4]

forEach,map异同:
共同:都会遍历数组,使用break也无法中断遍历。
不同:map需要返回值,返回值是一个与元素组长度相等的数组,forEach没有返回值。
第三类方法:every和some
every返回boolean型变量,是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true,否则返回false,遇到返回false项,则遍历终止。
some返回boolean型变量,是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true,遇到返回true项,则遍历终止。看看例子:

let arr = [9,10,3,4,2];
let everyResult = arr.every(function(value,index,obj){
    console.log(value);
    if (value > 3) {
        return true;
    }
});
console.log(everyResult);
//输出依次为: 9 10 3 false,即遍历至3时,返回false,退出遍历。整体返回值为false


let someResult = arr.some(function(value,index,obj){
    console.log(value);
    if (value === 4) {
        return true;
    }
});
console.log(someResult);
//输出依次为: 9 10 3 4 true,即遍历至4时,返回true,退出遍历。整体返回值为true。

第四类方法:reduce,reduceRight

let arr = [9,10,3,4,2];
//reduce会遍历数组,第一个参数preValue即回调函数上一次执行的返回值,若是第一次执行,则preValue是arr[0]
//curValue和index是循环遍历的当前值和索引,与其他遍历方法一致,obj是数组本身。
//下面这个就是数组求和
let sum = arr.reduce(function(preValue,curValue,index,obj){
    return preValue + curValue;
});
console.log(sum);//28

//reduceRight与reduce遍历方向不同,是从数组尾部开始,其他含义都一致。

5、其他操作(涉及方法:reverse,join)

reverse方法是用于倒置数组,join是连接数组,两个方法用法都很简单,不过过多介绍。
一个例子:将字符串倒置,如何实现。有一个简便的方法,就是利用split,reverse,join,如下:

let str = 'qwertyuio';
console.log(str);//qwertyuio
//先将字符串拆成数组,然后倒置,最后数组合并即可
console.log(str.split('').reverse().join(''));//oiuytrewq

到此为止,javascript中数组的常用方法以介绍完毕,欢迎批评指正,若果想和作者交流,请发信息至[email protected]

猜你喜欢

转载自blog.csdn.net/u011350550/article/details/81283850