ES6中数组的扩展(一)

扩展运算符

扩展运算符是(…),它好比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>]

函数调用中使用扩展运算符

	let arr = [10];
	function foo (array, ...items) {
		array.push(...items);
	}
	foo(arr, ...[15, 30, 50]);
	// [10, 15, 30, 50]

	function bar (x, y) {
		return x + y;
	}
	bar(...[6, 6])
	// 12

上面两个方法都使用了扩展运算符,扩展运算符会将数组转换为参数序列

扩展运算符与正常函数的参数结合使用

	function test (v, b, n, m, c) {
		return [v, b, n, m, c]
	}
	let arr = [10, 5];
	test(2, ...arr, 9, ...[7]);
	// [2, 10, 5, 9, 7]

扩展运算符的特殊写法

	let x = 1;
	let arr = ...[*x > 0 ? ['foo'] : []), ['bar']]
	// ['foo'], ['bar']
	
	let arr1 = [...[], 1]
	// [1]

只有函数调用时,扩展运算符才可以放在括号中

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

	(...[1, 2, 3])
	// error

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

扩展运算符可以把数组转为函数参数的缘故,使得apply方法不是首要选择了

	function foo (x, y, z) {
		return [x, y, z]
	}

	let args = [1, 3, 5];
	foo.apply(null, args);
	// [1, 3, 5]

	function bar (x, y, z) {
		return [x, y, z]
	}
	
	let args = [1, 3, 5];
	bar(...args);
	// [1, 3, 5]

扩展运算符的应用
(1)复制数组

数组是符合的数据结构,直接复制的话,只是复制了指向数据结构的指针,而不是克隆一个全新的数组

	let arr = [1, 2];
	let arr1;
	arr1 = arr;
	arr1[0] = 2;
	arr;
	// [2, 2]

上面的方式,arr1拿的只是arr的引用。
arr1和arr指向同一堆,所以arr1变,arr也会变。

	let arr = [1, 2];
	let arr1 = arr.concat();
	
	arr1[0] = 2'
	arr
	// [1, 2]

上面是使用克隆方法来创建新数组

使用扩展克隆数组

	let arr = [1, 2];
	// one
	let arr1 = [...arr];
	// [1, 2]
	arr1[0] = 2;
	arr
	// [1, 2]

	// two
	let [...arr1] = arr;

第二种显得不那么语义化,但以上两种arr1都克隆了arr

(2)合并数组

	// es5
	let arr = [1, 2];
	let arr1 = [3, 4];
	let arr2 = [5, 7];
	arr.concat(arr1, arr2);
	// [1, 2, 3, 4, 5, 7]

	// es6
	[...arr, ... arr1, ...arr2]
	// [1, 2, 3, 4, 5, 7]

	let a1 = [2, 6];
	let a2 = [3, 9];
	
	let a3 = a1.concat(a2);
	// [2, 6, 3, 9]
	let a4 = [...a1, ...a2];
	// [2, 6, 3, 9]
	

以上都是浅拷贝,指向的全部为引入地址,如果原地址内容发生改变,新变量也会跟着一起变动

(3)扩展运算符与解构赋值结合

	let [foo, ...bar] = [1, 3, 5, 6, 7];
	foo // 1
	bar // [3, 5, 6, 7]

	let [foo, ...bar] = []
	foo // undefined
	bar // []

	let [foo, ...bar] = ['foo'];
	foo // 'foo'
	bar // []
	
	const [first = 'first', ...rest] = [];
	first // 'first'
	rest  // []

	const [first = 'first', ...rest = [1, 3, 5, 7]] = [];
	// error
	// 扩展运算符不能使用默认值

扩展运算符用于数组赋值,必须在末尾,否则报错。

	let [bar, ...foo, baz] = [1, 3, 5, 6, 7];
	// error
	let [...bar, foo] = [1, 3, 4, 5 ,6];
	// error

仔细想一下,扩展会把所有剩余数组项都包括在内,所以后面不能有变量了

(4)字符串

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

其实就是使用的Iterator遍历器.

(5)实现了Iterator接口的对象

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

	let nodeList = document.querySelectorAll('div')
	let arr = [...nodeList];
	// ['div', 'div' ....];
	

上面nodeList是一个类数组,此时使用扩展运算符们就可以把它转换为真正的数组

对于数值,字符串,数组这些都部署了Iterator遍历器,自然使用扩展运算符可以实现遍历。

但是对象就无法实现了,因为对象身上没有部署Iterator遍历器

	let obj = {
		0: 'BMW'1: 'male',
		2: 'fanfan',
		length: 3
	}

	let newObj = [...obj];
	// error

但你可以使用Array.from 或者 手动为改实例添加Iterator遍历器,后续再说

(6)Map,Set解构, Generator函数

只要内部部署了Iterator遍历器,就可以使用扩展运算符把参数转为数组,换句话说扩展运算符就是调用的实例本身的Iterator遍历器

	let map = new Map();
	map.set([1, 'first']);
	map.set([2, 'last']);

	let newMap = [...map.keys()];
	// [1, 2, 3]

Generatror 函数在运行结束的时候会返回一个遍历器对象,因此你可以使用扩展运算符

	let g = function * () {
		yield 1;
		yield 2;
		yield 3;
	}

	[...g()]
	// [1, 2, 3]
	let obj = {car: 'BMW', wife: 'fanfan'};
	[...obj];
	// error

由于对象没有部署Iterator所以报错了

Array.from

Array.from方法用于将类数组对象和可遍历对象转为真正的数组

类数组转为真正数组

	let arrayLike = {
	    '0': 'a',
	    '1': 'b',
	    '2': 'c',
	    length: 3
	};

	// slice
	let arr1 = [].slice.call(arrayLike) // [a, b, c]

	// Array.from
	let arr2 = Array.from(arrayLike) // [a, b, c]

只要部署了遍历器对象的数据类型,都能转为数组

	Array.from('hello');
	// [h, e, l, l, o]
	Array.from(new Map([1, 'first'], [2, 'last']));
	// [[1, 'first'], [2, 'last']]	

扩展运算符其调用的就是Iterator遍历器对象,如果一个对象没有部署这个接口,那么就转换不了。

Array.from方法还支持类似数组的对象。所谓类似数组的对象,即必须拥有length属性

	Array.from({length: 3});
	// [undefined, undefined, undefined]

对于不兼容Array.from的浏览器可以使用slice兼容

	const toArray = (() =>
	  Array.from ? Array.from : obj => [].slice.call(obj)
	)();

	toArray({length : 3})

Array.from参数的第二个参数类似于过滤,可以把转换成功的数组每一个位拿来处理

	Array.from([1, 3, 5], (x) => x * x);
	// 1, 9, 25

	Array.from([1, 3, 5], x => x * x);
	// 等同于
	Array.from([1, 3, 5].map(x => x * x));

例子

	let spanText = docuemnt.querySelector('span');
	
	// map
	Array.prototype.map.call(spanText, x => x.textContent)

	// from
	Array.from(spanText, x => x.textContent)

数组中boolean为false转为0

	Array.from([1, 3, 5, 7,  , 10], x => x || 0);

返回多个数据类型

	function typeOf () {
		Array.from(arguments, x => typeof x)
	}
	typeOf(null, undefined, false, '', 123, [])

Array.from第三个参数用来绑定this

Array.from可以将任意值转为数组,并且提供map方法,这样一来,可以先转换数组,再对每一个值进行赋值或者替换

	let arr = Array.from({length : 3}, x => 'super');
	// [super, super, super]

Array.from 还可以用于字符串。
主要用来判断当前unicode字符,是否大于\uFFFF的Unicode字符,算作两个字符的bug

	function countString (string) {
		return Array.from(string).length
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值