数组的常用方法

 


数组的添加和删除

push()pop()

  这两个方法的功能与以前学的出栈和入栈方法是一样的,都是在原数组中操作的,并非生成一个修改后的新数组。push()在数组的尾部添加一个或多个元素,并返回数组新的长度;pop()删除数组的最后一个元素,减少数组长度并返回删除的值。

 

unshift()shift()

  类似于push()和pop(),只不过它们是在数组的头部进行添加和删除操作。unshift()是在数组头部添加一个或多个元素(将已存在的其他元素移动到更高索引的位置),返回数组的新长度;shift()则是删除数组的第一个元素并将其返回(删除后数组的其他元素会下移一个位置填充数组头部的空缺)。注意,使用unshift()一次性插入多个元素与多次调用unshift()插入多个元素的表现是不一样的,如下所示:

var a=[];
a.unshift(1);
a.unshift(2);
alert(a.toString());//a=[2,1]
a.unshift(3,4);
alert(a.toString());//a=[3,4,2,1],并非是像前面那样一个一个向头部插入
delete a[0];
alert(a.toString());//a=[,4,2,1],使用delete删除元素只是将该位置元素置为undefined,并不是从数组中移除

  在这里可以看到,使用delete删除数组元素并不会改数组的length属性,也不会将元素从高索引处下移来填充空缺位。这样,使用delete删除元素会使得数组变成稀疏数组

 

splice()

  该方法是在数组中插入或删除元素的通用方法,它会修改原数组的元素,并非是创建一个修改后的新数组。splice()有多个参数,功能如下:

  • 第一个参数:指定了插入和(或)删除的起始位置
  • 第二个参数:指定了要删除的元素个数
  • 随后任意多个参数:指定了需要插入的元素

  因此,根据提供参数的个数,splice()方法有多个实现功能:

  • 若仅提供了一个参数splice(a),splice()执行的是删除操作,表示从参数指定的起始位a开始到数组末尾的所有元素都将被删除;
  • 若提供了两个参数splice(a,b),仍是删除操作,表示从第一个参数指定的起始位a开始,删除b个元素;
  • 若提供两个以上参数,splice()会同时完成删除和插入操作(如果将第二个参数设为0,则只执行插入操作)。
    var a=[1,2,3,4,5,6,7,8];
    var n1=a.splice(4);//n1=[5,6,7,8],a=[1,2,3,4]
    var n2=a.splice(1,2);//n2=[2,3],a=[1,4]
    var n3=a.splice(1,0,'a','b');//n3=[],a=[1,'a','b',4]
    var n4=a.splice(1,2,[1,2],3);//n4=['a','b'],a=[1,[1,2],3,4]

 

concat()

  该方法用于在数组后面拼接新的元素,所要添加的元素作为参数传递到concat()方法中,这个方法不会修改原数组,返回的是新创建的拼接后的数组。值得注意的是:若参数包含数组,则拼接进来的是参数数组的元素,而不是将整个数组作为一个整体拼接进来,但它又不会递归扁平化数组的数组(也即作为参数的数组内部若还嵌套着数组,此时该嵌套的数组将作为一个整体拼接进来)。

var a=[1,2,3];
a.concat(4,5); //返回[1,2,3,4,5]
a.concat([4,5]);//返回[1,2,3,4,5]
a.concat([4,5],[6,[7,8]]);//返回[1,2,3,4,5,6,[7,8]],length=7

 

数组转换为字符串输出

join()

  该方法将数组中所有元素都转换为字符串并连接在一起,返回最后生成的字符串。它可以接收一个字符串参数用来作为分隔符,若不指定分隔符则默认使用逗号。

toString()

  与不使用任何参数调用join()方法返回的字符串是一样的。 

var a=[1,2,3];
a.join();// 输出"1,2,3"
a.join(" "); //输出"1 2 3"
a.toString(); //输出"1,2,3"

 

 

数组排序

reverse()

  该方法将数组中元素的顺序颠倒,返回逆序的数组。它在原数组的基础上改变,并非创建新的逆序后的数组。

sort()

  该方法将数组中的元素按字母表顺序排序并返回排序后的数组。同样,它也是在原数组的基础上进行更改。若想要按照其他方式进行排序,则可以向sort()方法传递一个比较函数。

var a=[33,4,1111,222];
a.sort(); //返回[1111,222,33,4],并非是我们以为的按数值大小排序
a.sort(function(a,b){     //按数值从小到大排序
            return a-b;
        });
a.sort(function(a,b){    //按数值从大到小排序
            return b-a;
        });        

 

数组切割

slice()

  该方法返回指定数组的一个片段或子数组,不会修改原数组。

var a = [1,2,3,4,5];
a.slice(0,3);//返回[1,2,3]
a.slice(3);//返回[4,5]
a.slice(1,-1);//返回[2,3,4]
a.slice(-3,-2);//返回[3]

 

map()

该方法接收两个参数:

  • 一个是callback函数,该方法会给原数组中的每个元素都执行一次callback函数,函数每次执行后的返回值依次作为新数组的元素。
  • 另一个是thisArg(可选),该参数的值作为callback函数的上下文,也即callback函数的this指针。

callback函数可以使用三个参数:

  • currentValue:正在处理的当前元素;
  • index(可选):正在处理的当前元素的索引;
  • array(可选):调用的数组;

 

误区

  我们使用parseInt()方法时,通常认为该函数会默认将传入的字符串转换为十进制整数(在MDN文档中,强烈要求使用parseInt()时传入第二个参数作为基数)。观察下面代码可以发现,执行结果并非我们所预期的那样:

const arr = ["1", "2", "3"].map(parseInt); //arr =  [1, NaN, NaN]

  因为在这里,parseInt接收了两个参数,第一个是数组中的元素作为传入的要转换的字符串,第二个是数组元素的索引作为传入parseInt的基。迭代步骤如下:

// parseInt(string, radix) -> map(parseInt(value, index))
/*  first iteration (index is 0): */ parseInt("1", 0); // 1
/* second iteration (index is 1): */ parseInt("2", 1); // NaN
/*  third iteration (index is 2): */ parseInt("3", 2); // NaN

  因此,应该指明传入parseInt()中的参数个数

const arr = ['1', '2', '3'].map( str => parseInt(str) ); //arr = [ 1, 2, 3 ]

 

手写实现map()方法

  (假设调用该方法的数组不是稀疏数组,也即索引值连续)

复制代码
/**
 * @param {Array} callback : 要执行的函数
 * @param {obj} context : callback函数的this对象
 * @return {Array} 
 */
Array.prototype.myMap = function (callback,context){
   if(this===null){
       throw new TypeError('this is null or not defined')
   }
   if(typeof callback !=='function'){
       throw new TypeError(callback + 'is not a function')
   }
   const arr = this; //要与context区分开,这里的this指向callback函数的直接调用者(原数组)
   const newArray = new Array(arr.length);
   for(let i = 0;i<arr.length;i++){
       newArray[i] = callback.call(context,arr[i],i,arr); //这里传入的context会作为callback函数的this对象
   }
   return newArray;
}
复制代码

 

reduce()

该方法接收两个参数:

  • 一个callback函数。数组中的每个元素按序执行callback函数,每一次执行的返回值会作为previousValue参数传入下一个元素的callback函数;
  • 一个initialvalue(可选)初始值。若指定了初始值,则callback函数从索引为0的元素开始执行(previousValue=initialValue,currentValue=arr[0]);若没有指定初始值,则将索引为0的元素作为previousValue,callback函数从索引为1的元素处开始执行。

callback函数可以使用三个参数:

  • previousValue:上一次调用callback函数时的返回值;
  • currentValue:正在处理的元素;
  • currentIndex:正在处理的元素的索引;
  • array:当前遍历的对象;

 

注意:当数组仅有一个元素且没有提供初始值innitailValue,或者提供了innitialValue而数组为空时,此唯一值将被直接返回,不会执行callback

 

使用reduce()实现map()

Array.prototype.mapUsingReduce = function (callback,context){
    let arr = this;
    let newArray = [];
    return arr.reduce((pre,cur,index)=>{
        pre[index] = callback.call(context,cur);
        return pre;
    },newArray)
}

 

使用ruduce()按顺序运行Promise

复制代码
function p1() {
    return new Promise((resolve, reject) => {
        resolve(5)
    })
}
function p2(a) {
    return new Promise((resolve, reject) => {
        resolve(a * 2)
    })
}
function f3(a) {
    return a * 3;
}
function p4(a) {
    return new Promise((resolve, reject) => {
        resolve(a * 4)
    })
}

const promiseArr = [p1, p2, f3, p4]

/**
 * @param {Array} arr : 包含多个Promise的列表
 * @param {Number} init : 初始值,封装成一个Promise。若没有指定,则会将undefined封装成一个Promise.
 * @return {Promise}
 */
function runPromiseInSequence(arr,init) {
    return arr.reduce((pre,cur)=>{
        return pre.then(cur)
    },Promise.resolve(init))
}

runPromiseInSequence(promiseArr,2).then(console.log)
复制代码

 

  首先,要明确各个函数都是异步操作,因此我们在执行reduce语句时,每次执行的返回值都是<pending>状态的Promise,整个循环实际上相当于Promise.then()的链式调用。

posted @   ˙鲨鱼辣椒ゝ  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示