一直以来都想把js中操作数组的所有方法进行一个汇总,今天终于完成了,希望可以给大家带来一些便利!
一、ES5数组操作方法
-
转换方法
toString()
:返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串
toLocaleString()
: 与toString()
功能一样,但底层调用但是toLocaleString()
方法
valueOf()
:返回数组
join()
:只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的使用传入分隔符拼接的字符串。var peoples = ["Dancy", "Echo", "Frocle"]; console.log(peoples.toString()); // Dancy,Echo,Frocle console.log(peoples.valueOf()); // ["Dancy", "Echo", "Frocle"] console.log(peoples.toLocaleString()); // Dancy,Echo,Frocle console.log(peoples.join()); // Dancy,Echo,Frocle console.log(peoples.join("-")); // Dancy-Echo-Frocle
-
栈方法
push
和pop
方法配合使用,可以实现栈
push()
: 将传入的数据添加到数组末尾,并返回修改后数组的长度
pop()
:从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项。var peoples = ["Dancy", "Echo", "Frode"]; var numl = peoples.push("Bob"); var num2 = peoples.push("Mary"); console.log("push返向的数组长度:",numl, num2); // push返回的数组长度:4 5 console.log(peoples); // ["Dancy", "Echo", "Frode", "Bob", "Mary"] var val = peoples.pop(); console.log("pop 返回的 val:", val); // pop返回的val: Mary console.log(peoples); // ["Dancy", "Echo", "Frode", "Bob"]
-
队列方法
push()
和shift()
配合使用,或者unshift()
和pop()
配合使用可以实现队列
shift()
: 从数组开头移除第一项,减少数组的length
值,然后返回移除的项。
unshift()
: 在数组开头添加任意个项并返回新数组的长度。var peoples = ["Dancy", "Echo", "Frode", "Bob"]; var shiftValue = peoples.shift(); console.log("shiftValue:", shiftValue); // shiftValue: Dancy console.log(peoples); ["Echo", "Frode", "Bob"] var unshiftVal = peoples.unshift("Yvonne"); console.log("unshiftVal:", unshiftVal); // unshiftVal: 4 console.log(peoples); // ["Yvonne", "Echo", "Frode", "Bob"]
-
重排序方法
reverse()
: 反转原数组,并返回被反转修改后的原数组var arr = [1, 2, 3, 4, 5]; var newArr = arr.reversed); console. log("newArr:", Arr); // newArr: [5, 4, 3, 2, 1] console.log("arr:", arr); // arr: [5, 4, 3, 2, 1] newArr.push(6); console.log(arr); // [5, 4, 3, 2, 1, 6]
sort()
:在默认情况下,sort()
方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。为了实现排序,
sort()
方法会调用每个数组项的toString()
转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()
方法比较的也是字符串。var arr = [0, 1, 5, 10, 15]; arr.sort(); alert(arr); //0,1,10,15,5
sort的用法:
sort()
方法可以接收一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面。比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数。
function compare(a, b) { if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } } var arr = [0, 1, 5, 10, 15]; arr.sort(compare); alert(arr); //0,1,5,10,15
比较函数的另一种写法:
function compare(a, b) { return a - b; // 若为b - a则sort排序结果为降序 } var arr = [1, 5, 15, 65, 22]; arr.sort(compare); console.log(arr); // [1, 5, 15, 22, 65]
-
操作方法
concat()
:会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有给
concat()
方法传递参数的情况下,它只是复制当前数组并返回副本。如果传递给
concat()
方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾
var peoples = ["Dancy", "Echo", "Frocle"]; var newPeoples = peoples.concat("Yvonne", ["Mary", "Bob"]); console.log(peoples); // ["Dancy", "Echo", "Frocle"]; console.log(newPeoples); // ["Dancy", "Echo", "Frocle", "Yvonne", "Mary", "Bob"];
slice()
: 基于当前数组中的一或多个项创建一个新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。
如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。
注意,slice()方法不会影响原始数组。var peoples = ["Dancy", "Echo", "Frocle", "Yvonne", "Mary", "Bob"]; var arr1 = peoples.slice(1); var arr2 = peoples.slice(1,4); console.log(arr1); // ["Echo", "Frocle", "Yvonne", "Mary", "Bob"] console.log(arr2); // ["Echo", "Frocle", "Yvonne"]
splice()
:
删除:指定 2 个参数,要删除的第一项的位置和要删除的项数。返回被删除的元素组成的数组。插入:提供 3 个参数,起始位置、0(要删除的项数)、要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。由于被删除项为0,故返回空数组
替换:指定 3 个参数,起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等,返回被删除的元素组成的数组。
splice()
方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组)。var peoples = ["Dancy", "Echo", "Frocle"]; var removed = peoples.splice(0, 1); // 删除第一项 console.log(peoples); // ["Echo", "Frocle"] console.log(removed); // ["Dancy"] 返回的数组中只包含一项 removed = peoples.splice(1, 0, "Mary", "Bob"); // 从位置 1 开始插入两项 console.log(peoples); // ["Echo", "Mary", "Bob", "Frocle"] console.log(removed); // 返回的是一个空数组 removed = peoples.splice(1, 1, "Yvonne", "Chris"); // 插入两项,删除一项 console.log(peoples); // ["Echo", "Yvonne", "Chris", "Bob", "Frocle"] console.log(removed); // ["Mary"],返回的数组中只包含一项
-
位置方法
indexOf()
:从数组的开头(0位置)开始向后查找
lastIndexOf()
:从数组的末尾开始向前查找这两个方法都接收两个参数:要查找的项和(可选)表示查找起点位置的索引。这两个方法都返回要查找的项在数组中的位置下标,或者在没找到的情况下返回-1。
-
迭代方法
every()
: 测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。注意:若收到一个空数组,此方法在一切情况下都会返回true。const isBelow40 = (currentValue) => currentValue < 40; const arr1 = [1, 30, 39, 22, 10, 13]; const arr2 = [1, 30, 39, 55, 10, 13]; console.log(arr1.every(isBelow40)); // true console.log(arr2.every(isBelow40)); // false console.log([].every(isBelow40)); // true
filter()
: 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。const peoples = ['Dancy', 'Yvonne', 'Echo', 'Chris', 'Bob', 'Mary']; const result = peoples.filter(name => name.length > 4); console.log(result); // ["Dancy", "Yvonne", "Chris"]
forEach()
: 对数组的每个元素执行一次给定的函数。const arr = ['a', 'b', 'c']; arr.forEach(val => console.log(val.toUpperCase())); // A // B // C
map()
: 创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。const arr = [1, 5, 10, 15]; const newArr = arr.map(x => x * 100); console.log(newArr); // [100, 500, 1000, 1500]
some()
: 测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。注意:如果用一个空数组进行测试,在任何情况下它返回的都是false。const array = [1, 2, 3, 4, 5]; const even = (element) => element % 2 === 0; console.log(array.some(even)); // true
-
归并方法
reduce()
: 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。使用: arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) callback: 执行数组中每个值 的函数,包含四个参数: accumulator 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。 currentValue 数组中正在处理的元素。 index 可选,数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。 array可选,调用reduce()的数组 initialValue 可选, 初始值,作为第一次调用callback函数时的第一个参数的值。如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
const arr = [1, 2, 3, 4]; const reducer = (accumulator, currentValue) => accumulator + currentValue; console.log(arr.reduce(reducer)); // 10 console.log(arr.reduce(reducer, 5)); // 15 5为initialValue // console.log([].reduce(reducer)); // 报错 Error: Reduce of empty array with no initial value // 注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
reduceRight()
: 接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。const arr = [[0, 1], [2, 3], [4, 5]].reduceRight( (accumulator, currentValue) => accumulator.concat(currentValue) ); console.log(arr); // [4, 5, 2, 3, 0, 1]
二、ES6新增数组操作
-
Array.from()
: 用于将类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set
和Map
)转为真正的数组let persons = { '0': 'Dancy', '1': 'Mary', '2': 'Echo', length: 3 }; // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['Dancy', 'Mary', 'Echo'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
实际应用中,常见的类似数组的对象是DOM操作返回的
NodeList
集合,以及函数内部的arguments
对象。Array.from
都可以将它们转为真正的数组。 -
扩展运算符(…): 可以将某些数据结构转为数组
// arguments对象 function fn() { var args = [...arguments]; // 展开参数 } // NodeList对象 [...document.querySelectorAll('div')]
扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。
-
Array.of()
:用于将一组值,转换为数组。Array.of(1, 2, 3) // [1,2,3]
-
数组实例的
copyWithin()
将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。Array.prototype.copyWithin(target, start = 0, end = this.length) // target(必需):从该位置开始替换数据。 // start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。 // end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。 // 这三个参数都应该是数值,如果不是,会自动转为数值。 [1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
-
数组实例的
find()
和findIndex()
find()
: 用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。[1, 4, -5, 10].find((n) => n < 0) // -5
findIndex()
:返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2
这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。另外,这两个方法都可以发现NaN,弥补了数组的IndexOf方法的不足。
[NaN].indexOf(NaN)// -1 [NaN].findIndex(y => Object.is(NaN, y)) // 0 Object.is() 方法判断两个值是否为同一个值。
-
数组实例的
fill()
使用给定值,填充一个数组。fill方法可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。['a', 'b', 'c'].fill(6) // [6, 6, 6] new Array(2).fill(5) // [5, 5]
-
数组实例的
entries()
,keys()
和values()
用于遍历数组。它们都返回一个遍历器对象,可以用for…of循环进行遍历,唯一的区别是:
keys()
是对键名的遍历
values()
是对键值的遍历
entries()
是对键值对的遍历for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b"
如果不使用
for...of
循环,可以手动调用遍历器对象的next
方法,进行遍历。let letter = ['a', 'b', 'c']; let entries = letter.entries(); console.log(entries.next().value); // [0, 'a'] console.log(entries.next().value); // [1, 'b'] console.log(entries.next().value); // [2, 'c']
-
数组实例的
includes()
返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes
方法类似。该方法属于ES7,但Babel转码器已经支持。
第二个参数表示搜索的起始位置,默认为0。
如果第二个参数为负数,则表示倒数的位置。如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。[1, 2, 3].includes(2); // true [1, 2, 3].includes(4); // false [1, 2, NaN].includes(NaN); // true
三、模拟实现数组的部分方法
-
forEach()
//模拟forEach函数 function forEach(array, fn) { for (let i = 0; i < array.length; i ++) { fn(array[i]) //用传进来的函数处理数组中的每一个元素 } } // 测试forEach let arr1 = [1, 2, 3, 4, 5] forEach(arr1, (item) => { // 接收从forEach函数中回传的参数 console.log(item) })
-
filter()
// 模拟filter function filter (array, fn) { let results = [] // 保存满足条件的值 for (let i = 0; i < array.length; i ++) { if (fn(array[i])) { // 满足fn中的条件时,push进results数组 results.push(array[i]) } } return results } // 测试filter let arr2 = [1, 3, 6, 4, 10] let results = filter(arr2, (item) => { // 获取数组中大于5的项并以数组形式返回 return item > 5 }) console.log(results) // 输出[6, 10]
-
once()
// 模拟once函数,让函数只执行一次 function once (fn) { let done = false return function () { // 这是返回的匿名函数 if (!done) { done = true // 这里的this就是fn,使用apply的目的是将匿名函数的参数展开并传给fn return fn.apply(this, arguments) } } } // 测试once let pay = once((money, other) => { // 通过apply展开了这里的参数,money、other console.log(`支付了:${money} RMB`) console.log(money, other) }) pay(5, 6) pay(5) pay(5) pay(5) // 调用了多次pay,但只执行了一次
-
map()
// 模拟map // 对数组中对每一个元素进行遍历,对每一个元素进行处理,并返回处理结果 const map = (array, fn) => { let results = [] for (let item of array) { // ES6 新遍历方式,对for循环对抽象,比for循环更简洁 // 将通过fn处理后对数组元素放入新数组 results.push(fn(item)) } return results } // map测试 let arr1 = [1, 2, 3, 5, 6] arr1 = map(arr1, v => v * v) console.log(arr1) // [1, 4, 9, 25, 36]
-
every()
// 模拟every // 判断数组中的每一个元素是否都匹配传入函数中指定都条件 const every = (array, fn) => { for (let item of array) { if (!fn(item)) { return false } } return true } // 测试every let arr2 = [1, 3, 6, 9, 23] let arr3 = [1, 3, 3, 0, 2] let result1 = every(arr2, v => v < 5) let result2 = every(arr3, v => v < 5) console.log(result1) // false console.log(result2) // true
-
some()
// 模拟some // 检测数组中是否有元素满足传入函数中指定的条件 const some = (array, fn) => { for (let item of array) { if (fn(item)) { return true } } return false } // 测试some let arr4 = [1, 2, 3, 4, 5] let r = some(arr4, v => v % 2 === 0) console.log('some:', r) // true
四、总结
-
不会改变原数组的方法
toString() toLocaleString() valueOf() join() slice() concat() indexOf() lastIndexOf()
-
会改变原数组的方法
push() pop() shift() unshift() reverse() sort() splice()
-
数组遍历方法
every() filter() forEach() map() some() reduce() reduceRight() 数组实例的entries(),keys()和values()
参考书籍:《Javascript高级程序设计(第三版)》
参考网站:
JavaScript MDN
ES6 文档