前面基础部分已经介绍过了数组, 这里再介绍一些高级的内容.
数组内的搜索
前面介绍过indexOf/lastIndexOf
和includes
find()
数组的find()
方法返回满足符合检验函数的第一个元素, 否则返回undefined
:
function isBigEnough(element) {
return element >= 15;
}
[12, 5, 8, 130, 44].find(isBigEnough);
130
这个方法语法为:find(function(item, index, array)
, 其中的那个函数会作用在每一个元素上, 各个参数为:
item
就是元素.index
是索引值.array
是数组本身.
当然, 使用之前介绍的箭头函数更好:
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
console.log(user.name);
John
其他两个参数很少会用到, 不做介绍了. findIndex()
用法没啥区别, 唯一不一样的就是返回是索引而不是元素值.
如果想要返回所有符合的元素呢? 可以使用filter()
filter()
用法和find()
一样: filter(function(item, index, array)
, 但是返回的符合元素组成的数组:
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);
console.log(someUsers); // 2
[ { id: 1, name: 'John' }, { id: 2, name: 'Pete' } ]
数组的变换
可以想象成空间的映射关系
map 映射
还是熟悉的味道:map(function(item, index, array)
:
let upperCase = ["Bilbo", "Gandalf", "Nazgul"].map( item => item.toUpperCase() );
console.log(upperCase);
[ 'BILBO', 'GANDALF', 'NAZGUL' ]
可见, 这就是对每个元素进行某个操作, 然后返回操作后的结果.
forEach
其实forEach
不应该放在这里, 但是这个方法和map
很像, 所以拿过来做一个比较. 用法与map
没有区别, 唯一不同是它没有返回值, 仅仅是对每个元素进行某操作:
["Bilbo", "Gandalf", "Nazgul"].forEach( item => console.log(item.toUpperCase()) );
BILBO
GANDALF
NAZGUL
undefined
sort 排序
这个方法直接介绍过, 这里在返回来看看:
let numArr = [ 1, 2, 15 ];
numArr.sort();
console.log(numArr);
[ 1, 15, 2 ]
看上面结果, 神奇吗? 排序结果完全不对啊! 这是为什么?
因为sort
默认里面要排序的是字符串, 对于字符串来说, 上面结果就没问题了.
那我想要对数字排序呢? 我们可以给sort()
传递一个排序函数, 根据返回的正负来排序:
function compareNumeric(a, b) {
if (a > b) return 1;
if (a == b) return 0;
if (a < b) return -1;
}
let numArr = [ 1, 2, 15 ];
numArr.sort(compareNumeric);
console.log(numArr);
[ 1, 2, 15 ]
因为仅仅能判断正负即可, 所以可以简化为:
numArr.sort( (a, b) => a - b );
console.log(numArr);
[ 1, 2, 15 ]
降维 reduce/reduceRight
我们使用map()
和forEach()
遍历数组, 使用某种方法处理数组, 但是并没有降低数组维度.
这里, 我们可以使用 reduce/reduceRight
来降低数组维度, 就是使一个一维数组变为零维, 也就是一个数字, 语法为:
let value = arr.reduce( function(previousValue, item, index, arr) { /*...*/ }, initialValue );
回调函数参数中的第二个开始的参数很熟悉了吧? 那么第一个参数呢?
previousValue
是之前调用结果的值.
另外initialValue
就是整个运算的初始值.
直接上例子看:
let arr = [1, 2, 3, 4, 5]
let sum = arr.reduce( (sum, current) => sum + current, 0 );
console.log(sum);
15
简单说, 就是sum
的初始值为0
, 第一次计算的时候, current
是第一个元素, 然后用sum
记录sum + current
, 然后以此类推.
不过我更喜欢用数学公式的方式说明这个问题, 因为我觉得它本来就是这样啊,:
这是一个递归公式, 其中\(N = n_0, n_1, … , n_m\)是一个数组, 我们想要计算它的累加, \(S_k\)为前\(k\)个元素的和.
上面的reduce()
语句的回调函数如果是任意一个函数, 初值为\(i_0\), 那么:
假设我要计算各个元素质积, 那么:
let product = arr.reduce( (product, current) => product * current, 1 );
console.log(product);
120
如果没有设初值, 那么初值为第一个元素, 然后从第二个元素开始计算
上面代码可以改写为:
let sumNoInit = arr.reduce( (sum, current) => sum + current );
console.log(sumNoInit);
let productNoInit = arr.reduce( (product, current) => product * current );
console.log(productNoInit);
15
120
reduceRight()
的区别仅仅是从最后一个(最右边)开始算起, 无他
可迭代对象(Iterables)
可迭代对象包含数组, 字符串等, 它们的特点就是可以使用for..of
循环:
let ages = [20, 30, 40, 50];
for(let age of ages) {
console.log(age);
}
20
30
40
50
let fullName = "Jim Clark Silver";
for(let name of fullName) {
console.log(name);
}
J
i
m
C
l
a
r
k
S
i
l
v
e
r
可见, 对于数组, 是元素为单位的遍历; 对于字符串, 是字母为单位的遍历.
似数组 (Array-likes)
似数组是有索引和长度的对象, 类似数组, 故而得名.
Array.from()
我们可以用Array.from()
方法将一个iterable或者array-like转变为Array:
let arrayLike = {
0: "Hello",
1: "World",
length: 2
};
let arr = Array.from(arrayLike);
console.log(arr)
console.log(arr.length)
[ 'Hello', 'World' ]
2
你还可以给Array.from()
提供一个映射方法:
let arrDouble = Array.from(arrayLike, ele => ele + ele);
console.log(arrDouble)
[ 'HelloHello', 'WorldWorld' ]