简单谈谈
ES5
中原本就提供了数组,这里谈谈数组下都有哪些方法新增,哪些方法进行了变更。
Array.from
在 javascript
中有这样一类的存在:类数组,它不是数组,却能像数组那么操作,如下便是一个类数组结构。
let arrayLike = {
"0": "a",
"1": "b",
"2": "c",
length: 3
};
类数组结构:可以像数组那样取值、 for
循环,但是却不能适用数组 forEach/splice
等数组特定的方法,在 ES5
中必须使用一些特殊的方法来将一个类数组结构转化成数组,而在 ES6
中, Array
对象下提供了 form
方法,该方法用于将一个类数组结构转化成一个真正的数组。
// ES5 的写法
var arr1 = [].slice.call(arrayLike); // ["a", "b", "c"]
// ES6 的写法
let arr2 = Array.from(arrayLike); // ["a", "b", "c"]
一些类数组
- 通过
DOM
操作返回的NodeList
集合。
let ps = document.querySelectorAll("p");
// 只有将 ps 转化成一个真正的数组才能使用 forEach 方法
Array.from(ps).forEach(function (p) {
console.log(p);
});
- 函数内部的
arguments
对象。
// arguments 对象
function foo() {
var args = Array.from(arguments);
console.log(args);
}
- 字符串。
var sArr = Array.from("hello");
console.log(sArr);
// ["h", "e", "l", "l", "o"]
Set
集合。
let namesSet = new Set(["a", "b"]);
Array.from(namesSet);
// ["a", "b"]
注: 只要是部署了 Iterator
接口的结构,都可以认为是类数组结构。
当然对一个数组使用 Array.from
是没有任何问题,只会将原来的数组结构复制一遍,并返回一个新的数组。(可以用这个来复制数组)
同时 Array.from
还可以接受第二个参数,作用类似与数组的 map
方法,用来对每个元素进行处理,然后返回一个新的数组。
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x);
// [1, 4, 9]
简单实用
- 实例1:取一组
DOM
节点的文本内容。
let spans = document.querySelectorAll("span.name");
let names2 = Array.from(spans, s => s.textContent);
- 实例2:将数组中布尔值为
false
的成员转为0
。
Array.from([1, , 2, , 3], (n) => n || 0);
// [1, 0, 2, 0, 3]
- 实例3:返回各种数据的类型
function typesOf () {
return Array.from(arguments, value => typeof value);
}
typesOf(null, [], NaN);
// ["object", "object", "number"]
- 实例4:只要有一个原始的数组结构就能构造出一个数组
Array.from({ length: 2 }, () => "jack");
// ["jack", "jack"]
Array.of
用于将一组值,转化为一组值。
Array.of(3, 11, 8); // [3, 11, 8]
Array.of(3); // [3]
Array.of(3).length; // 1
这个方法的主要目的,是弥补数组构造函数 Array()
的不足。因为参数个数的不同,会导致 Array()
的行为有差异。
Array.of
总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
copyWithin
用于在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
Array.prototype.copyWithin(target, start = 0, end = this.length);
注: 这里的 =
使用了函数中默认值的写法。
参数说明target
(必需)从该位置开始替换数据。start
(可选)从该位置开始读取数据,默认为 0
。如果为负值,表示取 长度 + start
。end
(可选)到该位置前停止读取数据,默认等于数组长度。如果为负值,表示取 长度 + start
。
[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]
更多的例子:
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]
// -2 相当于 3 号位,-1 相当于 4 号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1);
// [4, 2, 3, 4, 5]
// 将3号位复制到0号位
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
find & findIndex
方法效果find
找出第一个符合条件的数组成员findIndex
找出第一个符合条件的数组成员的位置
参数都为一个函数,用于做判断
// 找出第一个值小于 0 的数
[1, 4, -5, 10].find((n) => n < 0)
// -5
// 找出第一个值大于 9 的数
[1, 5, 10, 15].find((value, index, arr) => value > 9);
// 10
// 找出第一个大于 9 的数的位置
[1, 5, 10, 15].findIndex((value, index, arr) => value > 9);
// 2
若没有值符合,find
返回 undefined
,findIndex
返回 -1
。
fill
使用给定值,填充数组。
["a", "b", "c"].fill(7);
// [7, 7, 7]
new Array(3).fill(7);
// [7, 7, 7]
fill
方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
["a", "b", "c"].fill(7, 1, 2);
// ["a", 7, "c"]
entries & keys & values
方法效果entries
对键值对的遍历keys
对键名的遍values
对键值的遍历
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"
includes
表示某个数组是否包含给定的值,返回布尔值,与字符串的 includes
方法类似。
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, NaN].includes(NaN); // true
其他
这些常用,就不一一介绍了。
map
:提供对应关系,返回新数组。forEach
:遍历数组。filter
:过滤数组,返回符合要求的数组。reduce
:遍历数组,并累积值,从索引小的内容开始。reduceRight
:遍历数组,并累计值,从索引大的内容开始。every
:判断数组中元素是否都符合要求。some
:判断数组中是否有元素符合要求。sort
:将数组进行排序。
数组中的空位问题
数组中的空位是一个让人头疼的问题,空位有可能被忽略,而不是当成 undefined
来处理,比如:
forEach
、filter
、reduce
、reduceRight
、every
、some
会跳过空位。map
会跳过空位,但会保留这个值。
以下例子需要好好品品,品完过后放到浏览器上试试:
// 一个含有 4 个空位和一个元素的数组。
let emptyArr = [, , , , 1];
emptyArr.forEach(i => console.log("test"));
// 输出一次 test,空位被跳过了。
emptyArr.filter(i => {
console.log("test");
return true; // 将所有内容都返回
});
// 输出一次 test 空位被跳过,即使需要所有内容。
// 返回:[1]
emptyArr.reduce((acc, i) => {
console.log("test");
acc += 1;
return acc;
}, 0)
// 输出一次 test 空位被跳过。
// 返回:1
emptyArr.map(i => true);
// 返回:[, , , , true]
emptyArr.join();
// 返回:",,,,1"
emptyArr.toString();
// 返回:",,,,1"
let emptyArr2 = [, , , ,];
emptyArr2.every(i => {
console.log("test");
return true;
})
// 无输出,空位被跳过。
// 返回:true
emptyArr2.some(i => {
console.log("test");
return true;
})
// 无输出,空位被跳过。
// 返回:false
但并非所有的空位都会被跳过,如下所示:
Array.from(["a", , "b"]);
// [ "a", undefined, "b" ]
[, "a", "b", , ].copyWithin(2, 0);
// [,"a",,"a"]
let arr = [, ,];
for (let i of arr) {
console.log(1);
}
// 1
// 1
空格不会被跳过的方法:
- 处理成
undefined
的方法:entries
、keys
、values
、find
、findIndex
、扩展运算符(...
) - 保留空位:
copyWithin
、for...of
数组空位会导致各种奇奇怪怪的问题,解决方法只有一个:不创建带有空位的数组。