一、数组的增删改查
增加数组元素的方法有push / unshift,删除数组元素的方法有pop / shift,还有万能的增删改都可以的splice,以及查找数组元素的indexOf / lastIndexOf,下面我们一一讲解下区别。
1. push方法
从数组的最后插入(push压入)新元素,返回的结果是数组的长度。
var arr = [0, 1, 2, 3];
arr.push(4); // arr变成[0, 1, 2, 3, 4],此句执行的结果是arr.length即5
arr.push(5, 6); // arr变成[0, 1, 2, 3, 4, 5, 6],此句执行的结果是arr.length即7
2. pop方法
与push相对应的,pop是将数组的最后一个元素删除(pop弹出),返回的结果是被删除的该元素。
var arr = [1, 2, 3, 4];
arr.pop(); // arr变成[1, 2, 3],此句执行的结果是被删除的元素4
3. unshift方法
unshift也是插入新元素,不过是从数组的最开始插入,返回的结果也是插入后数组的长度。
var arr = [0, 1, 2, 3];
arr.unshift(4); // arr变成[4, 0, 1, 2, 3],此句执行的结果是arr.length即5
arr.unshift(5, 6); // arr变成[5, 6, 4, 0, 1, 2, 3],此句执行的结果是arr.length即7
4. shift方法
与unshift对应的,shift是删除最开始即第一个元素,返回的结果是被删除的该元素。
var arr = [1, 2, 3, 4];
arr.shift(); // arr变成[2, 3, 4],此句执行的结果是被删除的元素1
5. splice方法
splice方法就比较强大了,可以增加删除和查看元素,而且还可以指定位置。使用方法splice(index, num, value1, value2, ..., valuen),第一个参数是操作的位置,第二个参数是改变的元素个数,第三个是插入或替换的值,后面也都是要插入和替换的值。返回的结果是被改变元素构成的数组。
var arr = [1, 2, 3, 4];
// 增加元素,由于增加元素不会改变原数组元素的值,所以第二个参数为0
arr.splice(1, 0, 5); // 在数组下标为1即数组里元素2的位置,插入一个元素5,数组变为[1, 5, 2, 3, 4],此句返回结果是[](因为原数组没有被删除或替换的元素)。
arr.splice(0, 0, 6, 7); // 数组变为[6, 7, 1, 5, 2, 3, 4],返回的也是[]
// 删除元素,由于删除不需要新插入和替换的值,所以只需传前两个参数
arr.splice(0, 3); // 从index为0的位置开始,从左往右删除3个元素,数组变为[5, 2, 3, 4],此句返回的结果是[6, 7, 1]
arr.splice(3, 8); // 从index为3的位置开始,数组变为[5, 2, 3],此句返回[4]
// 替换元素,替换元素由于原数组的元素有变化,所以不为0,注意替换的个数和后面传的元素个数不一致可以做到替换的同时增删
arr.splice(0, 3, 1, 2, 3); // 从第一个元素开始,从左往右替换3个元素,数组变为[1, 2, 3],输出结果为被替换元素数组[5, 2, 3]
arr.splice(0, 2, 3, 2, 1, 2); // 替换的同时添加,此时arr为[3, 2, 1, 2, 3],返回结果[5, 2]
arr.splice(2, 3, 1, 0); // 替换的同时删除,此时arr为[3, 2, 1, 0],返回结果为[1, 2, 3]
或许有小伙伴已经被绕晕了,其实没必要记住那么多规律,知道每个参数代表啥再去推算就好,多看看例子就明白了。
6. indexOf和lastIndexOf方法
第一个参数指定查找元素,第二个参数指定从哪个位置开始找(没设默认0开始找),返回第一次被找到的下标值,若没有返回-1。而lastIndexOf基本类似,只是从最后一个元素开始倒着找。若第二个参数超出数组的长度范围,则直接返回-1。
var arr = ['str', 1, 2, 'str', 6];
arr.indexOf('str'); // 0
arr.indexOf('str', 1); // 4,从第二位开始往后找
arr.lastIndexOf('str'); // 4
arr.lastIndexOf('str', 1); // 0,从倒数第二位开始往前找
arr.indexOf('haha'); // -1
arr.indexOf('str', -1); // -1
arr.indexOf('str', 5); // -1
注意,其内部用的是严格等于(===)去比较是否相等,所以无法查找NaN,因为NaN===NaN返回false。
var arr = ['1', 1, 2, NaN];
arr.indexOf(1); // 1
arr.indexOf('1'); // 0
arr.indexOf(NaN); // -1
arr.lastIndexOf(NaN); // -1
二、数组的排序
1. sort方法
sort用于数组排序,会改变原数组,返回值是排好序的数组。有两种调用方式:
- 直接调用,则按默认排序。即按数字大小或字符串的unicode编码大小进行排序,对象会调用toString()再按编码排序,若有undefined则放在最后。
- 传自定义函数作为参数调用,当这个函数返回负值时表示第一个数应该位于第二个数前面,当返回0则相等,当返回正值时表示第一个数应该位于第二个数后面。
var arr1 = [1, 5, 2, 8, 6];
arr1.sort(); // [1, 2, 5, 6, 8]
var arr2 = ['1', '8', '7', '10'];
arr2.sort(); // ["1", "10", "7", "8"],字符串先比较的第一位的unicode编码值
// 为了得到正确的排序数组可以自定义函数
arr2.sort(function(a, b) {
return a - b; // 由于减法运算会先转数字再运算,所以可以正确排序
}); // ["1", "7", "8", "10"]
一般数字的对比,直接用减法就满足需求;如果是字符串要比较unicode值大小的,可以用><进行判断。看下面两个比较常见的例子:
// 要求按姓名进行排序
var users = [
{name: 'Peter', born: '2018-7-12'},
{name: 'Bake', born: '2018-3-15'},
{name: 'John', born: '2016-4-18'}
];
users.sort(function(a, b) {
if(a.name > b.name) {return 1;}
else if(a.name < b.name) {return -1;}
else {return 0;}
});
// [{name:"Bake", born:"2018-3-15"}, {name:"John", born:"2016-4-18"}, {name:"Peter", born:"2018-7-12"}]
// 要求按出生日期先后进行排序
users.sort(function(a, b) {
return new Date(a.born) - new Date(b.born);
});
// [{name:"John", born:"2016-4-18"}, {name:"Bake", born:"2018-3-15"}, {name:"Peter", born:"2018-7-12"}]
2. reverse方法
将数组进行逆序,会改变原数组,返回值会逆序数组。注意是逆序(反转下前后顺序),而不是倒序(按顺序递减排好)。
var arr = [1, 5, 3, 8, 6];
arr.reverse(); // [6, 8, 3, 5, 1]
三、数组的拼接
1. join方法
用指定参数作为分隔符连接数组元素,返回连接后的字符串。若没参数默认是','连接,若是有空位或undefined或null则转成空字符连接。
var arr = [1, 5, , 8, undefined, 6, null, 7];
arr.join('-'); // "1-5--8--6--7"
arr.join(); // "1,5,,8,,6,,7"
2. concat方法
concat用于数组或数组元素的合并,返回一个合并后的新数组,注意原数组不发生改变。
var arr1 = [1, 2], arr2 = [3, 4];
arr1.concat(arr2); // [1, 2, 3, 4]
arr1.concat({a: 1, b: 2}, {c: 3}); // [1, 2, {a:1, b:2}, {c:3}]
arr1.concat(3, 4, 5); // [1, 2, 3, 4, 5]
注意,若合并的元素是对象,则concat合并后的元素是引用,所以可以用来浅拷贝对象。
var arr = [1, 2, {a: 3, b: 4}];
var newArr = [].concat(arr); // 或者arr.concat(),都返回[1, 2, {a:3, b:4}]
newArr[2].a = 666;
console.log(arr); // [1, 2, {a:666, b:4}],由于是引用,所以原来arr的a也会被改变
四、数组元素处理
1. reduce方法
reduce方法接受两个参数,第一个参数是一个函数,第二个参数是默认初始值。而第一个函数也有两个参数,第一个参数是数组第一个元素或初始值或上一个函数返回的结果,第二个参数是数组的下个元素。来看个例子:
var arr = [1, 2, 3];
arr.reduce(function(a, b) {
return a + b;
});
// 第一次:没有初始值,a是数组第一个元素1,b是下个元素2
// 第二次:a是上次函数的结果3,b是下个元素3
// 没有下个数组元素,遍历结束,结果返回6
arr.reduce(function(a, b) {
return a + b;
}, 4);
// 第一次:有初始值,a是初始值4,b此时是第一个元素1
// 第二次:a是上次函数的结果5,b是下个元素2
// 第三次:a是上次函数的结果7,b是下个元素3
// 没有下个数组元素,遍历结束,结果返回10
一般尽量指定一个默认初始值,因为没有初始值对空数组reduce处理会报错。
[].reduce(function(a, b) {
return a + b;
}); // Uncaught TypeError: Reduce of empty array with no initial value
[].reduce(function(a, b) {
return a + b;
}, 0); // 0
reduce主要用处是存储上个元素遍历的处理结果,用于下个元素处理,来看看两个例子:
(1)找最大长度字符串
['hello js', 'hello', 'js'].reduce(function(longest, value) {
return value.length > longest.length ? value : longest;
}, '');
// "hello js"
(2)数组元素去重
// 合并两个数组,当cardUrl一样时保留arr1的元素
var arr1 = [
{url:'/a',cardUrl:'rUbAF3EFJjyyfYRrU3zIj2Ez'},
{url:'/b',cardUrl:'JnAfYbvqaQfy6bqyeiEjIZjm'},
{url:'/c',cardUrl:'7r2MFfzyQVryeEVVf2QfU7nq'},
],
arr2 = [
{url:"/d",cardUrl:"nua67bfa6n2qr2eUJbimeaQj"},
{url:'/e',cardUrl:"rUbAF3EFJjyyfYRrU3zIj2Ez"},
];
let arr = [...arr1,...arr2]; // 拼接数组,相当于concat
let hash = {};
arr = arr.reduce(function(item, next) { // 如果已存在则丢弃,否则放入结果集
hash[next.cardUrl] ? '' : hash[next.cardUrl] = true && item.push(next);
return item;
}, []);
/* [
{url: "/a", cardUrl: "rUbAF3EFJjyyfYRrU3zIj2Ez"},
{url: "/b", cardUrl: "JnAfYbvqaQfy6bqyeiEjIZjm"},
{url: "/c", cardUrl: "7r2MFfzyQVryeEVVf2QfU7nq"},
{url: "/d", cardUrl: "nua67bfa6n2qr2eUJbimeaQj"}
] */
2. reduceRight方法
此法与reduce用法基本一致,只是遍历的时候是倒序遍历。
var arr = [1, 2, 3];
arr.reduceRight(function(a, b) {
return a + b;
}, 4);
// 第一次:有初始值,a是初始值4,b此时是倒数第一个元素3
// 第二次:a是上次函数的结果7,b是倒数第二个元素2
// 第三次:a是上次函数的结果9,b是倒数第三个元素1
// 没有倒数第四个数组元素,遍历结束,结果返回10