数组修改方法
在数组那一章已经介绍了push,pop,shift和unshift方法,接下来这里再记录数组的其他常用方法。
splice()
前面我们知道要删除对象的属性可以用delete关键字,数组也一样,例如:
let arr = ["I", "go", "home"];
delete arr[1]; // remove "go"
alert( arr[1] ); // undefined
// now arr = ["I", , "home"];
alert( arr.length ); // 3
这里要注意的是,delete只是移除了数组指定索引号的元素的值,此时该元素还占据着索引位置,只不过为空,数组的length还是没变。
splice方法的出现可以解决这种问题,它彻底地移除了指定的数组元素,同时数组的length也会修改,例如:
let arr = ["I", "study", "JavaScript"];
arr.splice(1, 1); // from index 1 remove 1 element
alert( arr ); // ["I", "JavaScript"]
这里arr.splice(1,1)的第一个1表示索引号,第二个1表示要移除元素的个数
splice方法还可以用来添加元素,例如:
let arr = ["I", "study", "JavaScript", "right", "now"];
// remove 3 first elements and replace them with another
arr.splice(0, 3, "Let's", "dance");
alert( arr ) // now ["Let's", "dance", "right", "now"]
或者在不删除元素的情况下来添加元素,例如:
let arr = ["I", "study", "JavaScript"];
// from index 2
// delete 0
// then insert "complex" and "language"
arr.splice(2, 0, "complex", "language");
alert( arr ); // "I", "study", "complex", "language", "JavaScript"
let arr = [1, 2, 5];
// from index -1 (one step from the end)
// delete 0 elements,
// then insert 3 and 4
arr.splice(-1, 0, 3, 4);
alert( arr ); // 1,2,3,4,5
let arr = ["I", "study", "JavaScript", "right", "now"];
// remove 2 first elements
let removed = arr.splice(0, 2);
alert( removed ); // "I", "study" <-- array of removed elements
slice()
slice()用来截取数组,它返回一个新的数组,这一点slice()和字符串的slice()很像,例如:
let str = "test";
let arr = ["t", "e", "s", "t"];
alert( str.slice(1, 3) ); // es
alert( arr.slice(1, 3) ); // e,s
alert( str.slice(-2) ); // st
alert( arr.slice(-2) ); // s,t
concat()
concat()方法用来连接其它数组,例如:
let arr = [1, 2];
// merge arr with [3,4]
alert( arr.concat([3, 4])); // 1,2,3,4
// merge arr with [3,4] and [5,6]
alert( arr.concat([3, 4], [5, 6])); // 1,2,3,4,5,6
// merge arr with [3,4], then add values 5 and 6
alert( arr.concat([3, 4], 5, 6)); // 1,2,3,4,5,6
也可以用来连接对象,例如:
let arr = [1, 2];
let arrayLike = {
0: "something",
length: 1
};
alert( arr.concat(arrayLike) ); // 1,2,[object Object]
//[1, 2, arrayLike]
但是,如果被连接对象里有[Symbol.isConcatSpreadable]属性,则该属性不会被连接进去,例如:
let arr = [1, 2];
let arrayLike = {
0: "something",
1: "else",
[Symbol.isConcatSpreadable]: true,
length: 2
};
alert( arr.concat(arrayLike) ); // 1,2,something,else
数组元素查找
indexOf()/lastIndexOf()/includes()
数组的元素查找方法和字符串的查找很像,例如:
let arr = [1, 0, false];
alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1
alert( arr.includes(1) ); // true
有一点要注意的是,这些方法内部都是用了===来判断,如果数组元素为特殊关键字NaN,includes()会正确处理,而indexOf()和lastIndexOf()则不会,例如:
const arr = [NaN];
alert( arr.indexOf(NaN) ); // -1 (should be 0, but === equality doesn't work for NaN)
alert( arr.includes(NaN) );// true (correct)
find()/findIndex()
find()的语法如下:
let result = arr.find(function(item, index, array) {
// should return true if the item is what we are looking for
});
item:要查找的元素对象;
index:查找元素的索引号;
array:数组本身;
如果数组里的元素是对象,例如方法等,这时候我们就要用find()/findIndex()了,例如:
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // John
findIndex()用于返回要查找元素对象的索引号,由于它和find()很像,就不详解
filter()
filter()的语法如下:
let results = arr.filter(function(item, index, array) {
// should return true if the item passes the filter
});
上面的find()查找的是一个元素,filter()用于查找多个元素,例如:
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
// returns array of the first two users
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
数组的转换
map()
map()的语法如下:
let result = arr.map(function(item, index, array) {
// returns the new value instead of item
})
map()会遍历数组的每个元素并返回新的数组,返回数组的值就是你在map方法里操作的结果,而原数组内容不会发生变化,例如:
let arr = ["Bilbo", "Gandalf", "Nazgul"];
let lengths = arr.map(item => item.length);
alert(lengths); // 5,7,6
alert(arr); // Bilbo,Gandalf,Nazgul
sort()
sort()方法默认是以string的类型进行排序,例如:
为了能够对数字类型进行排序,我们需要再定义一个比较函数作为sort()的参数,例如:
比较函数还有以下两种推荐的简便写法,例如:
let arr = [ 1, 2, 15 ];
// the method reorders the content of arr (and returns it)
arr.sort();
alert( arr ); // 1, 15, 2
为了能够对数字类型进行排序,我们需要再定义一个比较函数作为sort()的参数,例如:
function compare(a, b) {
if (a > b) return 1;
if (a == b) return 0;
if (a < b) return -1;
}
function compareNumeric(a, b) {
if (a > b) return 1;
if (a == b) return 0;
if (a < b) return -1;
}
let arr = [ 1, 2, 15 ];
arr.sort(compareNumeric);
alert(arr); // 1, 2, 15
比较函数还有以下两种推荐的简便写法,例如:
let arr = [ 1, 2, 15 ];
arr.sort(function(a, b) { return a - b; });
alert(arr); // 1, 2, 15
arr.sort( (a, b) => a - b );
reserve()
我们可以使用reserve()方法来对数组内容进行反转,例如:
let arr = [1, 2, 3, 4, 5];
arr.reverse();
alert( arr ); // 5,4,3,2,1
reduce()和reduceRight()
reduce()用来遍历数组并且设置一个变量来记录操作结果,它的语法如下:
let value = arr.reduce(function(previousValue, item, index, arr) {
// ...
}, initial);
previousValue:我们设置的变量;
item:数组遍历到的当前元素;
index:当前元素的索引;
arr:当前数组;
initial:表示设置的变量的初始值;
下面这个例子就很详细了:
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
数组遍历
forEach()
forEach()可以用来遍历数组,它的语法如下:
arr.forEach(function(item, index, array) {
// ... do something with item
});
要注意的是,方法参数里的操作不会修改原数组的内容,例如:
let arr = ["Bilbo", "Gandalf", "Nazgul"]
arr.forEach((item, index, array) => {
item = "111";
});
alert(arr); // Bilbo,Gandalf,Nazgul
Array.isArray()
用typeof来判断对象是否为数组并不能达到我们的预想,因为数组也是对象,例如:
不过Array提供了一个内置方法来判断数组,例如:
alert(typeof {}); // object
alert(typeof []); // object
不过Array提供了一个内置方法来判断数组,例如:
alert(Array.isArray({})); // false
alert(Array.isArray([])); // true
可选方法参数thisArg
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg is the optional last argument
thisArg表示this对象,用于绑定方法里的this,例如:
let user = {
age: 18,
younger(otherUser) {
return otherUser.age < this.age;
}
};
let users = [
{age: 12},
{age: 16},
{age: 32}
];
// find all users younger than user
let youngerUsers = users.filter(user.younger, user);
alert(youngerUsers.length); // 2