Part3 数组的扩展
3.1 扩展运算符和数组的解构赋值
(1)扩展运算符是三个点 ...
,扩展运算符主要用于函数调用,它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
- 合并数组
arr.push(...arr1);
let arr = [1, 2, 3];
arr.push([4, 5, 6]);
arr
// [1, 2, 3, Array(3)]
我们想把[4, 5, 6]数组通过arr.push()方式合并到arr上;显然我们这样做没有成功。es5也有可以合并数组的方法通过arr.concat([4, 5, 6])
来实现, es6添加的扩展运算符可以实现,可读性更好。
let arr1 = [4, 5, 6];
arr.push(...arr1);
arr
// [1, 2, 3, Array(3), 4, 5, 6]
上面的例子,是扩展运算符的一个简单运用,简单理解就是把数组拉平。arr.push(...arr1)
使用了扩展运算符。将数组numbers展开后,一个个插入到arr数组里。
- 扩展运算符可以将nodeList类数组对象转为真正的数组
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
querySelectorAll方法返回的是一个nodeList对象。nodeList对象不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组,原因就在于NodeList对象实现了 Iterator 。
(2)扩展运算符与解构赋值结合
{
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
}
{
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
}
(3)扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错
{
const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错 :Rest element must be last element
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错:Rest element must be last element
}
数组的解构赋值在主站中的一个简单应用
let [obj, $UI] = [{}, $('body')];
// 等同于
let obj = {};
let $UI = $('body');
3.2 Array.from()
es6对数组扩展Array.from方法,用于将类数组转换真正的数组,并且对数组里面的元素遍历操作,再返回一个新数组。
Array.from(arrayLike, => )
Array.from方法,可以将类数组对象转为真正的数组。
为什么要es6要扩展Array.from()? 是因为扩展运算符不能展开类数组,会直接报错。当然es5也可以通过[].slice.call(arrayLike)
将arrayLike转为真正的数组,但是使用起来并不是很简洁方便,于是es6对数组扩展Array.from方法,可以直接将arrayLike转为真正的数组。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// 报错: Cannot spread non-iterable object.
let arr = [...arrayLike];
// ES5的写法:将类数组转化为数组
var arr2 = [].slice.call(arrayLike);
[...arr2] // ['a', 'b', 'c']
Array.from方法可以将具有具有Iterator接口的类似数组的对象转换为对象,扩展运算符背后调用的是遍历器接口,本质特征只有一点,任何有length属性的对象,都可以通Array.from方法转为数组。
Array.from还可以接受第二个参数,用来对每个元素进行处理,将处理后的值放入返回的数组。
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
Array.from还可以传入第三个参数。当map函数里面用到了this关键字,Array.from接受的第三个参数,用来绑定map函数中this指向的对象。
{
let obj = {
handle (n){
return n + 2;
},
newArr () {
let newArr = Array.from([1, 2, 3, 4, 5], (x) => {
return this.handle(x);
});
console.log(newArr); // [3, 4, 5, 6, 7]
}
};
obj.newArr();
}
3.3 Array.of
Array.of方法用于将一组值,转换为数组。Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。
Array.of(item1, item2, ...)
Array.of(3, 11, 8); // [3,11,8]
Array.of(3); // [3]
Array.of(3).length; // 1
es5�的Array方法也可以实现,为什么有要扩展一个Array.of方法呢?
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
因为当Array方法没有参数表示创建一个新数组;一个参数时,实际上是制定数组的长度,表示创建一个以参数长度的数组。几种情况返回的结果不一致。es6针对这个问题给数组扩展了Array.of方法。
3.4 find(), findIndex()
从语义上来看,这两个都是查找,一个是按照数组成员找,一个是按照数组成员的索引来找。
arr.find((当前的值, 前的位置, 原数组) => {})
arr.findIndex((当前的值, 当前的位置, 原数组) => {})
find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
[1, 5, -10, 15].find((value) => value < 0);
// -10
[1, 5, -10, 15].find((value, index) => value < index );
// -10
[1, 5, -10, 15].find((value, index, arr) => value > 9 );
// 15
findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。也可以接受三个参数,依次为当前的值、当前的位置和原数组。
[1, 5, -10, 15].findIndex((value) => value > 9); // 3
[1, 5, -10, 15].findIndex((value, index) => value > 1 && index >= 1); // 1
[1, 5, -10, 15].findIndex((value, index, arr) => value > 9 && index > 1 && arr.length > 3); // 3
3.5 includes()
includes方法与字符串的includes方法类似。用于搜索数组中是否包含某个值,若有返回true,若没有返回false。
在es6之前数组有indexOf方法,用于检查是否包含某个值,若包含返回该值首次出现的位置,若不包含返回-1。
indexOf方法有两个缺点:
- 一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。
- 二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判。
[NaN].indexOf(NaN)
// -1
es6为了避免这个问题,给数组扩展了includes方法,includes使用的是不一样的判断算法。
[NaN].includes(NaN)
// true
react项目中单选反选功能中的includes()应用
constructor(props) {
super(props);
this.state = {selected: []};
}
handleRowSelect(i) {
let selected = this.state.selected;
if (selected.includes(i)) {
let itemIdx = selected.indexOf(i);
selected.splice(itemIdx, 1);
} else {
selected.push(i);
}
this.setState({selected: selected});
}
记得第一节字符串的扩展中includes()对于ios8以下还有兼容性问题,目前不建议在主站中使用。
3.6 keys(), values(), entries()
es6 给数组扩展了三个新方法keys(), values(), entries(),用于遍历数组。它们的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。使用for...of循环进行遍历。
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"
Chrome 还未实现Array.prototype.values()
3.7 fill()
fill方法使用给定值,填充一个数组。fill方法三个参数,分别用于,要填充的元素、指定填充的起始位置和结束位置。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 2)
// ["a", "b", 7]
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
上面代码表明,fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
小结
-
扩展运算符主要用于函数调用
-
数组的解构赋值
-
Array.from()
将类数组转化为数组 -
find()
,findIndex()
查找数组成员 -
includes()
搜索数组中是否包含某个值
网友评论