javascript数组方法总结
疑问?
关于数组的方法,繁多且参数不一,如果不进行一次完整的总结,很容易混淆用法或者遗漏API中有的方法,导致重复造轮子或者简单问题复杂化,所以接下来通过总结所有常用数组方法,通过是否改变原数组,参数的比对,功能的归纳来总结javascript中的数组方法
步骤:
数组方法总览
首先我们需要总览js中的常用数组方法
我们可以先从对数组处理基本的概念开始分类:比如,增 删 改 查
增删改查分类
通过上图我们可以发现,在数组中增,删,查都非常简单并且可以见名知意,看起来js中数组处理方法很多,分好类发现其实都很好总结归纳,但接下来并不会直接开始从增删改查这样的分组开始讲,那样js的数组方法分类仍然杂乱无章,比如删功能模块中的splice是一个常用的可以有三个参数的剪切数组的方法,却和pop和shift这样简单的方法分为一类,有种强求一起的感觉,所以接下来通过是否改变原数组和基础数组操作和函数式操作来分类这些方法,方便最后分类讲解数组方法时可以通过前面的分类对该函数有清晰的认知
是否改变原数组
会改变原数组中的数据的原生数组方法:push,pop,shift,unshift,splice,sort,reverse
在项目中最明显的展现是否改变原数据方法的区别:不会改变原数组数据的数组方法会返回一个新的数组需要接收,而改变了原数组数据的方法不用接收数据,直接调用便完成操作
并且从这个图中可以发现,不会改变原数组并且不是查询的方法基本上就是函数式编程最常用的方法了
接下来我们从会改变原数组数据的数组方法开始理解起:
基本的增删:pop push shift unshift
arr.push(...items)—— 从尾端添加元素,arr.pop()—— 从尾端提取元素,arr.shift()—— 从首端提取元素,arr.unshift(...items)—— 从首端添加元素。
一排解释以完成,需要明确这些方法都是会改变原数组数据的,要是原数组数据不希望改变可以先赋值给变量保存
基本的原数组处理: sort reverse splice
1.splice
这个数组方法可选三个参数,用活了可以完成添加,删除,插入元素,远不止初始定义的截取
arr.splice(start[, deleteCount, elem1, ..., elemN])
它从索引 start 开始修改 arr:删除 deleteCount 个元素并在当前位置插入 elem1, ..., elemN。最后返回已被删除元素的数组。(并且会修改原数组数据)
//基本使用
let arr = ['I', 'am', 'cumin','of','course'];
arr.splice(1,1); // 从索引1开始删除1个元素
alert(arr); // ['I','cumin','of','course']
//替换
let arr1 =['I', 'am', 'cumin','of','course']; // 注意改变了原数组,所以重写一个
arr1.splice(2,2,'really?');
alert(arr1); // ['I','am','cumin','really?']
//插入
let arr2 =['I', 'am', 'cumin','of','course'];
arr2.splice(3,0,'Kasumi'); // 注意插入的话会插在索引之前
alert(arr1); // ['I','am','cumin','Kasumi','of','course']
splice的索引支持负数表示负向,将会从数组末尾开始计算
2.sort
arr.sort 方法对数组进行 原位(in-place) 排序,更改元素的顺序。(译注:原位是指在此数组内,而非生成一个新数组。)
它还返回排序后的数组,但是返回值通常会被忽略,因为修改了 arr 本身。
这些元素默认按照字符串进行排序 比如 : 15 < 2
所以我们可以提供一个函数作为参数,所以sort也可以函数式编程
arr.sort(fn);
// fn 返回正数表示大于,返回负数表示小于
// arr.sort(function(a, b) { return a - b; }); 就是经典的比较数字的fn比较函数
arr.sort( (a, b) => a - b ); // ES6 箭头函数简洁版
3.reverse
arr.reverse方法用于颠倒 arr 中元素的顺序。
let arr = [1, 2, 3, 4, 5, 6];
arr.reverse();
alert(arr); // 6,5,4,3,2,1
查询数组中的特定项
indexOf , lastIndexOf , find , findIndex , includes 都是查询数组中的特定项的方法
arr.indexOf(item, from)从索引from开始搜索item,如果找到则返回索引,否则返回-1。arr.lastIndexOf(item, from)—— 和上面同理,但是从右向左搜索。arr.includes(item, from)—— 从索引from开始搜索item,如果找到则返回true反之fasle。
注意这些比较是严格的相等,搜索false不会等同于0,只有数组真的包含false时才会返回索引
let result = arr.find(function(item, index, array) {
// 如果返回 true,则返回 item 并停止迭代
// 对于假值(falsy)的情况,则返回 undefined
});
// item 是元素 index 是它的索引 array 是数组本身 是经典的函数式方法
let users = [
{id: 1, name: "cumin"},
{id: 2, name: "Kasumi"},
{id: 3, name: "Jsaon"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // cumin
arr.findIndex 方法(与 arr.find 方法)基本上是一样的,但它返回找到元素的索引,而不是元素本身。并且在未找到任何内容时返回 -1。
常用函数式编程方法
我们可以发现不会改变原数组数据,且非查询的方法都是经典常用的数组方法,它们都会返回一个经过处理的新数组
比如:map slice filter reduce concat split reducrRight join
因为经典且常用,接下来一个个分析
concat()
arr.concat创建一个新数组,其中包含来自于其他数组和其他项的值。
arr.concat(arg1, arg2...)
let arr = [1, 2];
alert( arr.concat([3, 4]) ); // 1,2,3,4
alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6
alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
// 无论数组还是单个数据都会被添加在原数组末尾
let obj = { id: 001 , name: 'cumin' }
alert(arr.concat(obj)); // 1,2,[object Object] 对象会被整体加入
//如果类似数组的对象具有 Symbol.isConcatSpreadable 属性,那么它就会被 concat 当作一个数组来处理:此对象中的元素将被添加:
//[Symbol.isConcatSpreadable]: true,
split() && join()
str.split(delim(分隔符)) 方法可以做到。它通过给定的分隔符 delim 将字符串分割成一个数组。
let names = 'cumin Kasumi jason';
let arr = names.split(' '); // 以空格为分割符
for (let name of arr) {
alert( `A message to ${name}.` ); // A message to cumin(和其他名字)
}
// split 方法有一个可选的第二个数字参数 —— 对数组长度的限制。如果提供了,那么额外的元素会被忽略。\
let arr1 = 'cumin, Kasumi, Jason, ming'.split(', ', 2);
alert(arr1); // cumin, Kasumi
// 如果split 提供空参数,将会将字符串拆分为字符数组
arr.join(glue(胶水))与 split 相反。它会在它们之间创建一串由 glue 粘合的 arr 项。 返回字符串
reduce() && reduceRight()
arr.reduce 方法和 arr.reduceRight方法。它们用于根据数组计算单个值。
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
// accumulator迭代器在数组每个元素中不断经过计算,最后返回该数据
accumulator—— 迭代数,是上一个函数调用的结果,第一次等于initial(如果提供了initial的话)。item—— 当前的数组元素。index—— 当前索引。arr—— 数组本身。
应用函数时,上一个函数调用的结果将作为第一个参数传递给下一个函数。
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, item) => sum + item, 0);
// 函数返回的值就是下一次迭代数的值,如果没有初始值,迭代数会将第一个元素作为初始值。并从第二个元素开始迭代
// 注意不设初始值的话,空数组该方法会报错
alert(result); // 15
arr.reduceRight和 arr.reduce方法的功能一样,只是遍历为从右到左。
slice()
它会返回一个新数组,将所有从索引 start 到 end(不包括 end)的数组项复制到一个新的数组。start 和 end 都可以是负数,在这种情况下,从末尾计算索引。
arr.slice([start], [end]) // 注意取左不取右 , 是一个左闭右开区间 [a,b)
let arr = ["c", "u", "m", "i", "n"];
alert( arr.slice(1, 3) ); // u,m(复制从位置 1 到位置 3 的元素)
alert( arr.slice(-2) ); // i,n(复制从位置 -2 到尾端的元素)
我们也可以不带参数地调用它:arr.slice() 会创建一个 arr 的副本。其通常用于获取副本,以进行不影响原始数组的进一步转换。
map()
arr.map 方法是最有用和经常使用的方法之一。
它对数组的每个元素都调用函数,并返回结果数组。
let result = arr.map(function(item, index, array) {
// 新创建的数组接收的是返回新值而不是当前元素
})
let lengths = ["cumin", "Kasumi", "Jason"].map(item => item.length);
alert(lengths); // 5,6,5
filter()
find 方法搜索的是使函数返回 true 的第一个(单个)元素。
如果需要匹配的有很多,我们可以使用 arr.filter(fn)
语法与 find 大致相同,但是 filter 返回的是所有匹配元素组成的数组:
let results = arr.filter(function(item, index, array) {
// 如果 true item 被 push 到 results,迭代继续
// 如果什么都没找到,则返回空数组
});
总结。
通过重新总结和分类我们可以有条理的分出js数组中的各个方法使用用途了,通过本文还能清楚的了解那些方法是对原数组进行修改,那些方法返回新的数组,适合函数式编程,接下来就是需要 案例来练习新的理解了