### array * 数组转换方法 * 栈方法 * 队列方法 * 排序方法 * 操作方法 * 位置方法和查找方法 * 迭代方法 * 归并方法 * * * * * > 除Object类型外,Array可能是ECMAScript中最常用的类型了,而且ECMAScript中的数组与其他语言中的数组有着很大的区别,ECMAScript中的数组的每一项都可以保存任何类型的数据,而且,ECMAScript中对数组大小是可以动态调动的,即可随着数据的增加缩减自动容维。在javascript中定义数组有如下几种方式: ~~~ /*构造函数方式创建*/ let a = new Array() //创建一个空数组 let b = new Array(3) //创建一个长度为3的数组 /*字面量方式创建*/ let c = [] //创建一个空数组 let c = [1,2,3,4] //创建一个长度为4的数组,其中每一项包含一个数字 ~~~ > 与对象一样,在使用数组字面量定义数组时,不会调用Array()构造函数 #### 数组转换方法 > 如之前所述,所有对象都具有toLocaleString() / toString() / valueOf()方法,其中,调用数组对toString()方法会返回数组中每个值的字符串形式拼接而成的一个以逗号分隔带字符串。而调用valueOf()返回的还是原数组,而toLocaleString()一般返回的值都与toString()相同,如下: ~~~ let c = [1,2,3,4] console.log(c.toString()) // 1,2,3,4 console.log(c.valueOf()) // [1,2,3,4] console.log(b.toLocaleString()) // 1,2,3,4 ~~~ > 同时ES6也为我们提供了将数据结构转为数组的方法Array.from,它可以将类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map),代码如下: ~~~ let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c'] ~~~ > ES6新增Array.of方法,用于将一组值转换为数组。代码如下: ~~~ Array.of(3, 11, 8) // [3,11,8] ~~~ > Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。 #### 栈方法 > 在理解栈方法之前,先来理解一下“栈”的数据结构,即“最新添加的项最早被移除”。而栈中“项”的推入(数组中的插入)和弹出(数组中的移除),只发生在一个位置“栈的顶部”,ECMAScript专门提供了数组的push()方法和pop()方法来实现类似栈的行为。push()方法可以接收人意数量的参数(上面已经说过了,javascript数组对存储的数据类型没有限制),把他们逐个添加到数组末尾,并返回修改后的数组长度。pop()方法则是删除数组的最后一项,减少数组的length值,然后返回移除的项。如下: ~~~ let w = ["andy","tom"] console.log(w.pop()) // 返回字符串tom,此时数组中只有[ "andy" ] 一项了 console.log(w.push("tom","jack")) //返回数组w的length值3,此时数组已变为[ "andy","tom","jack"] ~~~ #### 队列方法 > 栈数据结构的访问规则是后进先出,而队列数据结构的访问规则是先进先出,队列从数组的末端添加项,从数组的前端移除项。实现这一操作的数组方法就是shift(),它能够移除数组中第一项并返回该项,同时数组长度减1,结合shift()和push()方法就可以像使用队列一样操作数组。如下: ~~~ let w = ["andy","tom"] console.log(w.shift()) // 返回字符串andy,此时数组中只有[ "tom" ] 一项了 console.log(w.push("andy","jack")) //返回数组w的length值3,此时数组已变为[ "tom","andy","jack"] ~~~ > javascript还提供了unshift()方法,顾名思义,该方法与shift()方法用途相反,它能在数组前端添加任意个项,并返回数组长度,因此同时使用unshift()和pop()方法,就可以从相反的方向来模拟队列,如下: ~~~ let w = ["andy","tom"] console.log(w.pop()) // 返回字符串tom,此时数组中只有[ "andy" ] 一项了 console.log(w.unshift("tom","jack")) //返回数组w的length值3,此时数组已变为[ "tom","jack","andy"] ~~~ #### 排序方法 > 在javascript数组中已经存在两个方法可以直接用来排序:reverse()和sort(),reverse()方法用来反转数组项的顺序,如下: ~~~ let n = [1,2,3,4,5] console.log(n.reverse()) // [5,4,3,2,1] ~~~ > sort()方法按升序排序,即按值从小到大排序。如下: ~~~ let n = [1,2,5,4,3,18,10] console.log(n.reverse()) // [1,2,3,4,5,10,18] ~~~ #### 操作方法 >concat()方法可以基于当前数组中的所有项创建一个新数组,具体来说这个方法会先创建一个当前数组的副本,然后将接收到的参数添加到这个副本的末尾,最后返回新建的数组,如下: ~~~ let a = [1,2] let b = a.concat(5,[3,4]) console.log(b) // [1,2,5,3,4] ~~~ > slice()方法可以继续数组中的一个或多个项创建一个新数组,slice方法接收一个或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始位置和结束位置之间的项,但不饱和结束位置的项。 > 注意:slice()方法不会影响原数组,如下: ~~~ let s1 = [1,2,3,4,5] let s2 = s1.slice(1) let s3 = s1.slice(1,3) console.log(s2) // 2,3,4,5 console.log(s3) // 2,3,4 ~~~ > 敲黑板:⚠️ 下面介绍splice(),与上面的slice()不是一个方法,一定要擦亮双眼看清楚!!!splice != slice > splice()方法可以说是javascript数组操作中最强大的方法了,它有很多种用法,它的主要用途是项数组中部插入项,具体有如下三种方式: > * 删除:splice(0,2)会删除数组前两项,显而易见,它第一个参数是起始位置,第二个参数是操作项的个数,而不是结束位置!!!⚠️ > * 插入:可以指向任意位置插入任意数量的axing,只需要提供3个参数:起始位置/要删除项的个数(0表示不删除,适合插入时使用)/要插入的项,如果要插入多个项,可以再传入第四/第五/第六...个参数。例如:splice(2,0,"andy","tom")会从当前位置2开始插入字符串"andy"和"tom"。 > * 替换:如上插入的第二个参数(要删除的项的个数)是0,表示不删除,那么我们可以将0改为我们想要替换掉的项的个数,来删掉需要替换掉项,来达到替换掉目的。 > 上面操作方法等实际案例如下: ~~~ let i = ["andy","tom","jack"] i.splice(0,1) //删除数组i的第一个项 console.log(i) // ["tom","jack"] i.splice(1,0,"小明"] // 在数组i的位置1后面插入一个项"小明" console.log(i) // ["tom","jack","小明"] i.splice(2,1,"andy") //在数组i的位置2后面删除一项,然后插入一个项"andy" console.log(i) // ["tom","jack","andy"] ~~~ #### 位置方法和查找方法 > 与之前的String字符串的位置方法一样,数组实例也有两个相同的位置方法:indexOf()和lastIndexOf(),在数组实例中的indexOf()方法和lastIndexOf()方法接收两个参数:要查找的项和(后面一个参数可选)起点位置索引。其中indexOf()方法从数组开头向后匹配,lastIndexOf()方法从数组末尾开始向前匹配,这两个方法都返回要查找的项在数组中的索引位置,或者在没有找到的情况下返回-1,在匹配的过程中会使用全等符(===)也就是说:匹配项与参数必须是严格等于,案例如下: ~~~ let n = [1,2,3,4,5,6] console.log(n.indexOf(4)) // 3 console.log(n.lastIndexOf(4)) // 3 console.log(n.indexOf(4,4)) // -1 console.log(n.indexOf(4,2)) // 3 ~~~ > 数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。代码如下: ~~~ [1, 4, -5, 10].find((n) => n < 0) //找出数组中第一个小于0的成员 -5 ~~~ > 数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1,该方法接收三个参数:当前值/当前索引/数组本神。代码如下: ~~~ [1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) //返回第一个小于9的项的位置索引 2 ~~~ #### 迭代方法 > ECMAScript5为数组定义了5个迭代方法,每个方法都接收两个参数:要在每一项上运行的函数和运行该函数函数的作用域(影响this值)。传入这些方法的函数会接收三个参数:数组项的值/该项在数组中的位置和数组对象本身。根据使用方法不同,这个函数执行后的返回值会(也可能不会)影响方法的返回值。主要是如下5个方法: > every() :对数组中的每一项运行给定函数,如果该函数对数组的每一项都返回true则返回 true。如下,将数组中的每一项转为一个浮点数,全部转换成功就会返回true,但并不会改变原数组的值。 ~~~ ["1","2","3"].every(parseFloat) // true ~~~ >filter():对数组中的每一项运行给定函数,返回该函数中会返回true的项组成的数组。如下,我们继续用上面的例子来解释: ~~~ ["1","2","Andy"].filter(parseFloat) // ["1","2"] // 因为Andy这个字符串强制转换浮点数之后它也不是一个数字,所以返回了false,filter就返回了他为true的成员 ~~~ > forEach() : 遍逆数组中的每一项,并向每一项给定函数,这个方法没有返回值。这个方法与使用普通的for循环一样,不明白的可以自己试试。 > map() : 对数组中的每一项运行给定函数,返回每次函数调用的结果组成数组。 ~~~ ["1","2","Andy"].map(parseFloat) // [1, 2, NaN] // 如上:Andy这个字符串强制转换浮点数之后它也不是一个数字,即非数值 NaN ~~~ > some():对数组中的每一项运行给定函数,如果该函数对任意项返回true,则返回true。 ~~~ ["tom","jack","Andy"].some(parseFloat) // false // 因为数组中的成员强制转换浮点数之后都是NaN,所以返回false,但如果把数组中任意一项改为数字字符串,那parseFloat就可以将它转为浮点数,some函数久会返回true ~~~ > ES6为数组新增了一种遍逆方法:for...of,用for...of进行数组遍历 ~~~ for(let index of [1,2,3,4,5]){ console.log(index) } // 1 2 3 4 5 ~~~ #### 归并方法 > ES5中定义了两个数组归并方法:reduce()和reduceRight()这两个方法都会迭代数组所有的项,然后构建一个最终返回的值。其中,reduce()方法从数组的第一项开始,逐个遍逆到最后。而reduceRight()方法则从数组的最后一项开始,向前遍逆到第一项。 > 这两个方法都接收两个参数:一个在每一项上调用的函数和一个(可选的)作为归并基础的初始值。传给reduce()he reduceRight()的参数中的第一个函数接收4个参数:前一个值/当前值/项的索引/和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。 ~~~ let u = [1,2,3] //正序 let n = u.reduce(function(prev,cur,index,arr){ return cur+1 }) //倒序 let b = u.reduceRight(function(prev,cur,index,arr){ return cur +1 }) console.log(n) console.log(b) // 4 返回的是数组最后一项+1 // 2 返回数组第一项+1 ~~~