您的位置 首页 php

第20节 数组的操作及遍历-Web前端开发之Javascript-王唯

本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。

数组的操作:

concat()方法:

基于当前数组,将多个元素连接一起成为新的数组并返回;新数组中的元素按连接时的顺序排列。(具体来说,这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。当需要合并多个数组时,此方法比较方便);

语法:数组名.concat( [ item1, [ item2, [ item3 , […, [ itemN ] ] ] ] ] );

item:可选项,可以是数组对象也可以是单个数组元素,或者是其它对象;

  var  arr = [1,2];arr = arr.concat();arr = arr.concat(3,4);arr = arr.concat(3,[4,5]);arr = arr.concat([3,4],[5,6]);arr = arr.concat([3,4],[5,6,[7,8]]);console.log(arr);  

concat()不会递归扁平化数组的数组,也不会修改原来的数组;当没有给concat()方法传递参数的情况下,它只是复制当前数组并返回副本。

slice()方法:

能够基于当前数组中的一个或多个项创建一个新数组;

语法:slice(start [, end]);

其接受一或两个参数,即要返回项的起始和结束位置;在只有start一个参数的情况下,slice()方法返回从该位置开始到当前数组末尾的所有项;如果两个参数,该方法返回起始和结束位置之间的项,但不包括结束位置的项;

其不会影响原有数组;如:

 var colors=["red","green","blue","yellow","purple"];var c = colors.slice(1);c = colors.slice(1,4);c = colors.slice(1,-2);c = colors.slice(-4,-2);c = colors.slice(3,1);console.log(colors);console.log(c);  

如果slice()方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置;(如,在一个包含5项的数组上调用 slice(-2,-1)与调用slice(3,4)得到的结果相同;)

如果结束位置小于起始位置,则返回空数组。

splice()方法:

可以删除、替换或插入数组元素,是最强大的数组方法,有很多种用法;

具体作用是,从一个数组中移除一个或多个元素;剩下的元素组成一个数组,移除的元素组成另一个新数组并返回;同时,原数组可以在移除的开始位置处顺带插入一个或多个新元素,达到修改替换数组元素的目的;

语法:数组名. splice( start, deleteCount, [ item1 [, item2 [ , . . . [ , itemN ] ] ] ] );

start:必选项,表示从数组中剪切的起始位置下标索引号。

deleteCount:必选项,表示将从数组中切取的元素的个数。

item:可选项,表示切取时插入原数组切入点开始处的一个或多个元素;

  • 1)删除:可以删除任意数量的项,只需要指定2个参数,如:splice(0,2);// 删除数组中前两项;如果只指定1个参数,则删除从该位置到结尾的元素;
  • 2)插入:可以向指定位置插入任意数量的项,需要指定3个参数,其中第二个参数为0;如果要插入多个项,可再传入第4第5等任意多个项,如:splice(2,0,”red”,”green”);
  • 3)替换:可以向指定位置删除任意数量的项,同时插入任意数量的项,需要指定至少3个参数;插入的项数不必与删除的项数相等,如:splice(2,1,”red”,”green”);

splice()方法始终会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组);

 var a = [1,2,3,4,5,6,7,8];// var b = a.splice(4);// var b = a.splice(1,4);// var b = a.splice();// var b = a.splice(1,0,'a','b');// var b = a.splice(1,4,'a','b');var b = a.splice(1,4,['a','b']);console.log(a);console.log(b);  

区别于concat(),splice()会插入数组本身而非数组的元素;

第一个参数可以接受负数,如果为负数,则指定的位置是数组长度加上该负值,或者从后向前定位;

 var a = [1,2,3,4,5,6,7,8];var b = a.splice(-3, 2, 'a','b');console.log(a);console.log(b);  

在实际的场景中,主要还是向数组的中部插入项;

delete运算符删除数组元素:

通常使用delete运算符删除一个指定的元素(与删除对象属性一样):

 var colors=["red","green","blue","yellow","purple"];delete colors[1];console.log(colors);  

此删除并没有真正删除数组元素,仅删除元素内容;(此删除与为其赋undefined值是类似的,但有一些微妙的区别);

delete删除不会修改数组的length属性;如果从数组中删除一个元素,该数组就变成稀疏数组;

删除数组元素有多种方式,如设置length属性小于数据长度,会删除数组尾部的元素;另外,还有前面所讲的方法。

注:如果需要删除全部元素只需要删除数组对象即可;

数组元素位置:

有关数组元素位置的方法:indexOf()和lastIndexOf(),两者会搜索整个数组中具有给定值的元素,并返回要查找的元素在数组中的第一个索引位置,或者在没找到返回-1;

这两个方法都是接收两个参数:要查找的项和(可选的)表示查找起点位置的索引;其中,indexOf()方法从数组的开头(位置为0)开始向后查找,lastIndexOf方向则从数组的末尾开始向前查找。

注:在查找时,使用是全等操作符;

 var numbers = [1,2,3,4,5,4,3,2,1];console.log(numbers.indexOf(4));  // 3console.log(numbers.lastIndexOf(4));  // 5console.log(numbers.indexOf(4,4));  // 5console.log(numbers.lastIndexOf(4,4));  // 3 var p={name:"wangwei"};var p1 = p;var people = [{name:"wangwei"},{name:"dawei"}];var people = [p1,{name:"dawei"}];var morePeople = [p];console.log(people.indexOf(p));  // -1console.log(morePeople.indexOf(p));  // 0  

第二个参数也可以是负数,即为数组长度加上该负数的值为查找的索引开始位置,或者从后往前定位;

 var numbers = [1,2,3,4,5,4,3,2,1];console.log(numbers.indexOf(4,-5));  // 5  

封装一个函数,查找所有给定值的索引,并返回一个包含匹配索引的数组:

 var numbers = [1,2,3,4,5,4,3,2,1]; function  findAll(a,x){    var result = [],    // 将会返回的数组        len = a.length, // 待搜索数组的长度        pos = 0;        // 开始搜索的位置    while(pos < len){        pos = a.indexOf(x, pos);        if(pos === -1) break;        result.push(pos);        pos = pos + 1;    }    return result;}console.log(findAll(numbers,4));  

字符串也有indexOf()和lastIndexOf()方法,它们和数组的方法功能类似;

对于数组这些方法,也可以重写,本质上就是修改其prototype对象的属性方法,如:

 var arr = [1,2,3];arr.push(4,5);console.log(arr);Array.prototype.push = function(){    for(var i=0; i<arguments.length; i++)        this[this.length] = arguments[i] * arguments[i];}arr.push(6,7);console.log(arr);  

遍历数组:

所谓的数组的遍历就是通过索引挨个取出数组元素;遍历目的是为了读取所有元素或者处理所有元素;使用for循环是遍历数组最常见的方法:

 var citys = ["beijing","nanjing","bengbu"];for(var i = 0; i<citys.length; i++)    console.log(citys[i]);for(c in citys)console.log(c, citys[c]); var o = {name:"wangwei",age:18,sex:true};var keys = Object.keys(o);  // 获得o对象属性名组成的数组console.log(keys);var values = [];for(var i=0;i<keys.length; i++){    values[i] = o[keys[i]]; // 取得对象的属性值}console.log(values); // 优化的写法,数组的长度只查询一次for(var i=0, len = keys.length; i<len; i++){    values[i] = o[keys[i]]; // 取得对象的属性值} // 练习:分别输出数组中的偶数、求数组奇数和偶数的个数、平均值、最大值var arr = [1,3,16,8,57,22];var result = 0, evenLen=0, max = arr[0];for(var i=0; i<arr.length; i++){    result += arr[i];    if(arr[i] % 2 == 0){        console.log(arr[i]);        evenLen++;    }    if(max < arr[i])        max = arr[i];}console.log("偶数的个数:" + evenLen);console.log("和为:" + result);console.log("平均数:" + result / arr.length);console.log("最大值:" + max);  

在遍历稀疏数组,或者需要排除null、undefined和不存在的元素时,需要先检测:

 var arr = [1,,3,null,undefined,6];// 遍历所有for(var i=0,len=arr.length; i<len; i++)    console.log(i,arr[i]);// 跳过null、undefined和不存在的元素for(var i=0,len=arr.length; i<len; i++){    if(!arr[i]) continue;    console.log(i, arr[i]);}// 只跳过undefined和不存在的元素for(var i=0,len=arr.length; i<len; i++){    if(arr[i] === undefined) continue;    console.log(i, arr[i]);}// 只跳过不存在的元素for(var i=0,len=arr.length; i<len; i++){    if(!(i in arr)) continue;    console.log(i, arr[i]);}  

使用for/in遍历稀疏数组:

 for(var i in arr)    console.log(i, arr[i]);  

但是,for/in能够枚举继承的属性名,如添加到Array.prototype中的方法;由于这个原因,在数组上不应该使用for/in循环,除非使用额外的检测方法来过滤不用的属性,如:

 Array.prototype.company = "zeronetwork";var arr = [1,,3,null,undefined,6];arr.custom = "wangwei";arr[-18.1] = 18;// 只遍历元素for(var i=0,len=arr.length; i<len; i++)    console.log(i,arr[i]);// 把所有可枚举的属性全遍历出来for(var i in arr)    console.log(i, arr[i]); // 使用hasOwnProperty()方法过滤for(var i in arr){    if(!arr.hasOwnProperty(i)) continue;    console.log(i, arr[i]);}// 跳过不是非负整数的ifor(var i in arr){    if(String(Math.floor(Math.abs(Number(i)))) !== i) continue;    console.log(i, arr[i]);}  

ES允许for/in循环以不同的顺序遍历对象的属性;通常数组元素的遍历实现是升序的,但不能保证一定是这样的;特别地,如果数组同时拥有对象属性和数组元素,返回的属性名很可能是按照创建的顺序而非数值的大小顺序;如何处理这个问题的实现各不相同,如果算法依赖于遍历的顺序,那么最好不要使用for/in而使用常规的for循环。

遍历数组的迭代方法:

ECMAScript5为数组定义了5个迭代方法;这些方法的第一个参数接收一个函数,并且对数组的每个元素调用一次该函数;第二个参数是可选的:其是运行该函数的作用域对象(影响this的值);或者说:调用的函数被当作是第二个参数的方法;

如果是稀疏数组,对不存在的元素不调用传递的函数;

这些方法不会修改原始数组;

参数函数使用三个参数:数组元素、元素索引和数组对象本身;通常,只需要第一个参数,可以忽略后两个参数;

参数函数可以修改原始数组;

根据使用的方法不同,这个函数执行后的返回值可能也会不同;

forEach ()方法:

遍历数组,为每个元素调用指定的函数;该函数使用三个参数:数组元素、元素索引和数组本身;此方法没有返回值,本质上与使用for循环迭代数组一样;

 var numbers = [1,2,3,4,5,4,3,2,1];numbers.forEach(function(item,index,array){    console.log(item,index,array[index]);});// 为每个元素加1var data = [1,2,3,4];data.forEach(function(v,i,a){    a[i] = v + 1;});console.log(data);  

如果只关心数组元素的值,可以只使用一个参数,额外的参数将被忽略:

 // 求和var data = [1,2,3,4];var  sum  = 0;data.forEach(function(value){    sum += value;});console.log(sum);  

forEach()方法无法在所有元素都被传递给调用的函数之前终止遍历,即没有像for循环中使用的break语句;如果要提前终止,必须把forEach()方法放在try块中,并能抛出一个异常:

 function foreach(a,f,t){    try{a.forEach(f, t);}    catch(e){        if(e === foreach.break) return;        else throw e;    }}foreach.break = new Error("StopIteration");  

every()和some()方法:

最相似的是every()和some(),它们都是数组的逻辑判定:用于判定数组元素是否满足某个条件;

对every(),传入的函数必须对每一项都返回true,这个方法才返回true;

而some()是只要传入的函数对数组中的某一项返回true,就会返回true,否则返回false;

 var numbers = [1,2,3,4,5,4,3,2,1];var everyResult = numbers.every(function(item,index,array){    return (item > 2);});console.log(everyResult);  // falsevar someResult = numbers.some(function(item,index,array){    return (item > 2);});console.log(someResult);    // true  

一旦every()和some()确定该返回什么值时,它们就会停止遍历数组元素;(some()在判定函数第一次返回true后就返回true,但如果判定函数一直返回false,它将会遍历整个数组;every()恰好相反,它在判定函数第一次返回false后就返回false,但如果判定函数一直返回true,它将会遍历整个数组)。

根据数学上的惯例,在空数组上调用时,every()返回true,some()返回false;

filter()方法:

返回的是数组元素是调用的数组的一个子集;

回调函数 是用来逻辑判定的,该函数返回true或false;如果返回的是true或真值,则该函数处理的数组元素就被添加到返回的子集数组中;

filter()方法会跳过稀疏数组中缺少的元素,它的返回数组总是密集的;

 var numbers = [1,2,3,4,5,4,3,2,1];var filterResult =  number s.filter(function(item,index,array){    return item>2;});console.log(filterResult);var evenResult = numbers.filter(function(value,index){    return index % 2 == 0;  // [1, 3, 5, 3, 1] index是索引});console.log(evenResult);// 压缩稀疏数组var sparse = [1,,,4];var dense = sparse.filter(function(){    return true;});console.log(dense);// 压缩并删除undefined和null元素var sparse = [1,null,3,undefined,,6];var dense = sparse.filter(function(v){    return v !== undefined && v != null;});console.log(dense);  

map()方法:

将调用的数组的每个元素传递给回调函数,并将调用的结果组成一个新数组返回;其不会修改原始数组,如果是稀疏数组,返回的也是相同方式的稀疏数组,即具有相同的长度、相同的缺失元素;

 var numbers = [1,2,3,4,5,4,3,2,1];var mapResult = numbers.map(function(item,index,array){    return item*2;});console.log(mapResult);var a = [1,null,3,undefined,5];var b = a.map(function(v){    return v * v;});console.log(b);  

归并方法:

ECMAScript5还新增了两个归并数组的方法:reduce()和reduceRight();这两个方法都会迭代数组的所有项,然后构建一个最终返回的值;

其中,reduce()方法从数组的第一项开始,逐个遍历到最后;而reduceRight则从数组的最后一项开始,向前遍历到第一项;

语法:reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number;

这两个方法都接收两个参数:调用的函数callbackfn和作为归并基础的初始值initialValue(可选的);

这个函数接收4个参数:前一个值、当前值、项的索引和数组对象;其返回的任何值都会作为第一个参数自动传给下一项;第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项;

使用reduce()方法可以执行求数组中所有值之和的操作,如:

 // 求和var values = [1,2,3,4];var sum = values.reduce(function(prev,cur,index,array){    return prev + cur;});console.log(sum);   // 10  

说明:第一次执行回调函数,prev与cur分别为数组的第1和第2项,即prev是1,cur是2;第二次,prev是第一次执行的结果,即3(1+2的结果),cur是数组的第三项,即是3,以此类推;

reduce()参数函数的参数也可以只使用两个参数,如:

 // 求和var values = [1,2,3,4];var sum = values.reduce(function(prev,cur){    return prev + cur;});console.log(sum);   // 10// 求积var product = values.reduce(function(prev,cur){    return prev * cur;});console.log(product);  // 24// 求最大值var max = values.reduce(function(prev,cur){    return prev > cur ? prev : cur;});console.log(max);  // 4  

reduce()方法的第二个参数initialValue是回调函数的第一个参数previousValue的初始值;如:

 // 把以上所有示例添加第二个参数,如:var values = [1,2,3,4];var sum = values.reduce(function(prev,cur){    return prev + cur;},2);  // 12  

说明,第一次调用时,prev为initialValue值,即为2,cur为数组第一项,即为1;第二次调用,prev为3,cur为2,以此类推;

reduceRight()的作用类似,只不过方向相反,即按照数组索引从高到低(从右到左)处理数组;如:

 var values = [1,2,3,4,5];var sum = values.reduceRight(function(prev,cur,index,array){    console.log(prev,cur);    return prev + cur;},6);console.log(sum);  // 15// 求2^(3^4),乘方操作的优先顺序是从右到左var a = [2,3,4];var big = a.reduceRight(function(accu, value){    console.log(value);    return Math.pow(value, accu);});console.log(big);  

在空数组上,不带初始值参数的reduce()将导致类型异常;如果数组只有一个元素并且没有指定初始值,或者一个空数组并且指定了一个初始值,该方法只是简单的返回那个值而不会调用回调函数;

 var a = [];// var b = a.reduce(function(x,y){return x + y});  //no initial value// var b = a.reduce(function(x,y){return x + x});var b = a.reduce(function(x,y){return x + y},3);console.log(b);  

使用reduce()还是reduceRight(),主要取决于要从哪头开始遍历数组;除此之外,它们完全相同。

reduce()和reduceRight()是典型的函数式编程;有些地方,会把其回调函数称为化简函数,这个化简函数的作用就是用某种方法把两个值组合或化简为一个值,并返回化简后的值;如以上的示例,化简函数通过各种方法,组合了两个值。

976ff1cac87c4822b8afae9dfb2b1998

Web前端开发之Javascript-零点程序员-王唯

文章来源:智云一二三科技

文章标题:第20节 数组的操作及遍历-Web前端开发之Javascript-王唯

文章地址:https://www.zhihuclub.com/34916.shtml

关于作者: 智云科技

热门文章

网站地图