数组的扩展

扩展运算符

扩展运算符(…)相当于rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]

该运算符主要用于函数调用。

function push(array,...items){
	array.push(...items);
}
function add(x,y){
	return x+y;
}

const numbers=[4,38];
add(...numbers);//42

上面的代码中,array.push(…items)和add(…numbers)这两行,都是函数的调用,它们都是用了扩展运算符。该运算符将一个数组,变为参数序列。

扩展运算符后面还可以放置表达式。

const arr=[
	...(x>0?['a']:[]),
	'b',
];

注意,只有函数调用的时候,扩展运算符才可以放在圆括号中,否则会报错。

(...[1, 2])
// Uncaught SyntaxError: Unexpected number

console.log((...[1, 2]))
// Uncaught SyntaxError: Unexpected number

console.log(...[1, 2])
// 1 2

上面三种情况,扩展运算符都放在圆括号里面,但是前两种情况会报错,因为扩展运算符所在的符号不是函数调用。

替代函数的apply()方法

由于扩展运算符还可以展开数组,所以不再需要apply()方法将数组转为函数的参数了。

//ES5的写法
function f(x,y,z){
	//...
}
var args=[0,1,2];
f.apply(null,args);

//ES6的写法
function f(x,y,z){
	//...
}
let args=[0,1,2];
f(...args);

下面是扩展运算符取代apply()方法的一个实际的例子,应用Math.max()方法,简化求出一个数组最大元素的写法。

//ES5的写法
Math.max.apply(null,[14,3,77]);

//ES6的写法
Math.max(...[14,3,77]);

//等同于
Math.max(14,3,77);

另一个例子是通过push()函数,将一个数组添加到另一个数组的尾部。

//ES5的写法
var arr1=[0,1,2]
var arr2=[3,4,5]
Array.prototype.push.apply(arr1,arr2);

//ES6的写法
let arr1=[0,1,2]
let arr2=[3,4,5]
arr1.push(...arr2);

上面代码的ES5写法中,push()方法的参数不能是数组,所以只好通过apply()方法变通使用push()方法。有了扩展运算符,就可以直接将数组传入push()方法。

扩展运算符的应用

(1)复制数组
数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

const a1=[1,2];
const a2=a1

a2[0]=2;
a1 //[2,2]

上面代码中 ,a2并不是a1的克隆,而是指向同一份数据的另一个指针。修改a2,会直接导致a1的变化。
ES5只能用变通方法来复制数组。

const a1=[1,2];
const a2=a1.concat();

a2[0]=2;
a1 //[1,2]

上面代码中,a1会返回原数组的克隆,再修改a2就不会对a1产生影响。
扩展运算符提供了复制数组的简便写法。

const a1=[1,2];
//写法一
const a2=[...a1];
//写法二
const [...a2]=a1; 

上面两种写法,a2都是a1的克隆。

(2)合并数组
扩展运算符提供了数组合并的新写法。

const arr1=['a','b'];
const arr2=['c'];
const arr3=['d','e'];

//ES5的合并数组
arr1.concat(arr2,arr3);
//['a','b','c','d','e']

//ES6的合并数组
[...arr1,...arr2,...arr3]
//['a','b','c','d','e']

不过这两种方法都是浅拷贝,使用的时候需要注意。

(3)与解构赋值结合

扩展运算符可以与解构赋值结合起来,用于生成数组。

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

如果扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错

const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错

(4)字符串
扩展运算符还可以将字符串转为真正的数组。

[...'hello']
// [ "h", "e", "l", "l", "o" ]

(5)实现了Iterator接口的对象
任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。

let nodeList=document.querySelectorAll('div');
let array=[...nodeList];

上面代码中,querySelectorAll()方法返回的是一个NodeList对象。他不是数组,而是一个类似数组的对象 。这时,扩展运算符可以将其转为真正的数组,原因在于NodeList对象实现了Iterator。
(6)Map和Set结构,Generator函数
扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符,比如Map结构。

let Map=new Map([
	[1,'one'],
	[2,'two'],
	[3,'three'],
]);
let arr=[...map.keys()]; //[1,2,3]

Generator函数运行之后,返回一个遍历器对象,因此也可以使用扩展运算符。

const go=function*(){
	yield 1;
	yield 2;
	yield 3;
};
[...go()] //[1,2,3]

如果对没有Iterator接口的对象,使用扩展运算符,将会报错。

const obj = {a: 1, b: 2};
let arr = [...obj]; // TypeError: Cannot spread non-iterable object
Array.from()

Array.from()方法用于将两类对象转为真正的数组:类似数组的对象和可遍历的对象(包括ES6新增的数据结构Set和Map)。
下面是一个类似数组的对象,Array.from()将它转为真正的数组。

let arrayLike={
	'0':'a',
	'1':'b',
	'2':'c',
}
//ES5的语法
var arr1=[].slice.call(arrayLike);// ['a', 'b', 'c']

//ES6的写法
var arr2=Array.from(arrayLike); // ['a', 'b', 'c']

实际应用中,常见的类似数组的对象是DOM操作返回的NodeList集合,以及函数内部的arguments对象。Array.from()都可以将他们转为真正的数组。

只要是部署了Iterator接口的数据结构,Array.from()都能将其转为数组。

Array.from('hello')
//['h','e','l','l','o']

let nameSet=new Set(['a','b'])
Array.from(nameSet) //['a','b']

如果参数是一个真正的数组,Array.from()会返回一个一模一样的新数组。

Array.from([1, 2, 3])
// [1, 2, 3]
Array.of()

Array.of()方法用于将一组值,转换为数组。

Array.of(3,11,8) //[3,11,8]
Array.of(3) //[3]
Array.of(3).length //1

这个方法的主要目的,主要是为了弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

上面代码中,Array()方法没有参数、一个参数、三个参数的时候,返回结构都不一样。只有当参数个数不少于2个的时候,Array()才会返回由参数组成的新数组。参数只有一个正整数时,实际上是指定数组的长度。

Array.of()基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。他的行为非常统一。

Array.of()//[]
Array.of()//[undefined]
Array.of()//[1]
Array.of(1,2)//[1,2]

Array.of()总是返回参数值组成的数组。如果没有参数,就返回一个空数组。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值