本文只是作为ES6入门第九章学习笔记,在整理知识点的同时,会加入部分个人思考与解答,若想知道更详细的介绍,还请阅读阮一峰大神的ES6入门

一、拓展运算符

ES6中新增了拓展运算(...)三个点,它的作用是将一个数组或实现了Iterator接口的对象/类数组(nodeList,arguments)转为分隔的参数序列。

console.log(...['echo', '听风是风', '时间跳跃']); //echo 听风是风 时间跳跃

类数组arguments使用拓展运算符:

let fn = function () {
console.log(...arguments);
};
fn(1, 2, 3, 4); //1,2,3,4

数组拓展运算符与函数rest参数的区别:

比较巧的是,其实在ES6入门第八章函数拓展中,也有用三个小点且用于取代arguments的rest参数的rest参数。为了避免混淆两者,我们做个简单区分。

let fn = function (...rest) {
rest.forEach(ele => console.log(ele));
};
fn('听风是风', ...[1, 2, 3]); //听风是风 1 2 3 //等同于
fn('听风是风', 1, 2, 3);

rest参数作用是取代arguments,用于函数参数上,在函数内部使用rest参数时不需要带上...;数组拓展运算符更多用于函数调用上,且...必须带上。

//rest参数
let fn = function (...rest) {
//使用时...不需要带上
rest.forEach(ele => console.log(ele));
}; //数组拓展运算符
let arr = [1,2,3];
//使用时...永不离身
Math.max(...arr);//

rest参数必须写在函数参数末尾,否则标错;数组拓展运算符在函数调用时可以出现在任意位置,但需要注意的是只有函数调用时才能放在圆括号中,否则报错。

//错误用法,...rest只能出现在参数末尾
let fn = function (name, ...rest, age) {}; //错误用法,除非是函数调用,否则不能写在花括号中
(...[1,2,3]);

 二、拓展运算符的作用

1.取代apply方法

实际开发中我们常常需要通过apply或者call方法来调用某方法,但如果调用时参数是一个数组,就不得不使用apply,因为apply能将数组解析给单个参数传递给函数。

而拓展运算符刚好就具有将数组,类数组转为单个元素序列的功能,因此能很好的取代apply。比如函数应用:

let fn = (x, y, z) => console.log(x + y + z),
arr = [1, 2, 3];
//函数应用
//ES5
fn.apply(null, arr); //
// ES6
fn(...arr); //

还记得常用的数组取最大,最小值的方法吗。Math.max同样能够简写:

let arr = [1, 2, 3, 4, 5];
//ES5
Math.max.apply(null, arr); //
Math.min.apply(null, arr); //
//ES6
Math.max(...arr); //
Math.min(...arr); //

将一个数组的元素压入到另一个数组尾部(我之前都没想过用这个做法...):

let arr1 = [1, 2, 3],
arr2 = [4, 5, 6];
//ES5
Array.prototype.push.apply(arr1, arr2);
//ES6
arr1.push(...arr2);

2.合并/复制数组:

let arr1 = [1, 2, 3],
arr2 = [4, 5, 6],
arr3 = [7, 8, 9];
//ES5
let arr = arr1.concat(arr2, arr3);
//ES6
let arr = [...arr1, ...arr2, ...arr3];

顺带一提,concat方法不会修改原数组,而是复制数组中的元素组成并返回一个新数组,concat和拓展运算符合并数组的操作都是浅拷贝。

你肯定会想,不是说concat是浅拷贝吗,为啥我下面的修改合并的新数组没跟这变化:

let arr1 = [1, 2, 3],
arr2 = [4, 5, 6];
//ES5
let arr = arr1.concat(arr2);
arr1.push(10);
console.log(arr); //[1,2,3,4,5,6]

这是因为concat虽然操作的是数组,但是复制添加的不是整个数组,而是数组中的单个元素们,上述数组中的元素均为number类型,属于基础类型。

let arr1 = [{a:1}, {a:2}],
arr2 = [{c:3}, {d:4}];
//ES5
let arr = arr1.concat(arr2);
arr1[0]['a'] = 5;
console.log(arr); //[{a:5}, {a:2},{c:3}, {d:4}]

那我们将数组中的单个元素改为对象试试,可以看到修改arr1时会对arr数组造成影响,拓展运算符合并数组同为浅拷贝也是这个道理。

ES6入门这本书中也提到使用拓展运算符复制数组的操作,同样需要注意当元素是复杂数组类型会存在浅拷贝的问题。

let arr = [1,2,3,4];
//以下两种写法复制数组等效
arr1 = [...arr];
[...arr1] = arr;

 3.结合解构赋值实现快速赋值

我在ES6入门笔记第二篇中有记录解构赋值的使用,解构赋值同样能与数组拓展运算符结合使用,达到快速拆分数组分开赋值的目的。

let arr = [1, 2, 3, 4];
[a, ...b] = arr;
a//
b//[2,3,4]

对应位置去看,其实就是将数组第一位给了a,剩下的元素打包给了b,不难理解。

下面是数组元素不足,或者为空时使用解构赋值的情况:

let arr = [];
[a, ...b] = arr;
a //undefined
b //[] let arr1 = ['听风是风'];
[a1, ...b1] = arr1;
a1 //'听风是风'
b1 //[]

最后需要注意的一点是,如果结合解构赋值使用,拓展运算符必须写在参数最后一位,否则会报错。还记得吗,...rest参数也是必须写在函数参数最后一位。

let arr = [];
[...a, b] = arr; //报错

4.类数组转数组

在前面已经有提过,类数组(例如nodeList,arguments)结合拓展运算符能快速转为数组:

let P = document.querySelectorAll('p');
//获取页面所有p元素并修改文本内容
[...P].forEach(ele => ele.innerHTML = '听风是风');

5.将字符串快速转为数组

拓展运算符可以将字符串转为字符串使用

let name = 'echo';
//ES5
let name1 = name.split('');
// ES6
let name1 = [...name];
name1 //['e','c','h','o']

6.实现了Iterator接口的对象都能使用拓展运算符

拓展运算符解析原理其实就是内部调用了目标对象的遍历器接口(Symbol.iterator),只要具备Iterator接口的对象,都可以使用拓展运算符:

let map = new Map([
['听风是风', 1],
['echo', 2],
['时间跳跃', 3]
]);
[...map.keys()] //['听风是风','echo','时间跳跃']

二、Array.from()方法

1.基本用法

Array.from方法主要用途是将类数组(具有length属性)对象,或可遍历的对象转为真正的数组。

我们在前面已经使用拓展运算符将类数组nodeList和arguments转为了真正的数组,这里Array.from方法同样能做到。你肯定会想,既然拓展运算符可以做到,为什么还要新增这个方法,因为两者还是有区别的。

类数组对象是具有length属性的对象,nodeList,和arguments具有length属性的同时,其实还具有Iterator接口,所以拓展运算符才能调用Iterator接口转换。

比如下面两个类数组对象,都具有length属性但不具备iterator接口,Array.from方法可以转为数组,但拓展运算符不能做到:

let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5
let arr = Array.prototype.slice.call(arrayLike);
// ES6
let arr1 = Array.from(arrayLike);
arr; //['a','b','c'];
arr1; //['a','b','c'];
//拓展运算符无法转换不具有iterable接口的对象
[...arrayLike] //报错arrayLike is not iterable

再如只有length属性的类数组对象:

let obj = {
length: 3
};
Array.from(obj); //[undefined,undefined,undefined]
//同样拓展运算符无法转换
[...obj]; //报错

2.Array.from()方法的第二个参数

Array.from()方法的第二个参数类似与数组的map方法,用于对每个元素进行处理,并将处理后的结果放入返回的数组。

let arrayLike = {
'0': 1,
'1': 2,
'2': 3,
length: 3
};
// ES6
let arr1 = Array.from(arrayLike, ele => ele + 1); //[2,3,4]
// ES5
let arr2 = Array.prototype.map.call(arrayLike, ele => ele + 1); //[2,3,4]
// 等同于
let arr3 = Array.from(arrayLike).map(ele => ele + 1); //[2,3,4];

比如快速生成包含10个数字1的数组:

let arrayLike = {length: 10};
let arr = Array.from(arrayLike, () => 1);

三、Arrar.of()方法

Array.of()用于将一组值转为为数组,主要目的是弥补构造函数Array()的不足:

对于创建数组,我们常推荐数组直接量,而非使用数组构造函数创建,因为对于特殊情况会得到你不想要的值:

let arr = [3]; //[3]
//构造函数的坑
let arr1 = Array(3); //[undefined,undefined,undefined]
//Array.of可以弥补这点
let arr3 = Array.of(3) //[3]

如果不支持此方法,我们也可以模拟实现:

let ArrayOf = function () {
if (Array.of) {
return Array.of(...arguments);
} else {
return [].slice.call(arguments);
};
};
let arr = ArrayOf(1, 2, 3); //[1,2,3]

四、数组实例新增API

此方法用于数组复制指定位置开始到指定位置结束的成员到其它位置,修改原数组并返回。

Array.prototype.copyWithin(target, start = 0, end = this.length)
·target(必需):从该位置开始替换数据。如果为负值,表示倒数。
·start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
·end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数(也就是说复制不包含这一位)

看几个例子:

let arr = [1, 2, 3, 4, 5];
//正数下标 0 1 2 3 4
//负数下标 -5 -4 -3 -2 -1
//从下标2开始到下标3结束,但不包含下标3的元素,所以只有元素3,并复制到下标0处替换原有的元素
[1, 2, 3, 4, 5].copyWithin(0, 2, 3); //[3,2,3,4,5]
//从下标-3开始到下标-1结束,但不包含下标-1的元素,所以只有元素3,4,并复制到下标0处替换原有的元素
[1, 2, 3, 4, 5].copyWithin(0, -3, -1); //[3,4,3,4,5]

需要注意的是,在使用copyWidthin方法时,你的start元素位置必须在end元素位置左边,否则此方法将无效:

let arr = [1, 2, 3, 4, 5];
//起始元素均在结束元素右边,不会起作用
arr.copyWithin(0, 3, 2); //[1, 2, 3, 4, 5]
arr.copyWithin(0, -1, -3); //[1, 2, 3, 4, 5]

 2.find()与findIndex()

find方法在开发中使用频率很高,它能帮你找到第一个符合条件的对象并返回,并且跳出循环,如果未找到则返回undefined。

let arr = [1, 2, 3, 4, 5];
var ele = arr.find(ele => ele > 3);
ele //

find方法的回调函数接受三个参数:

arr.find(function (ele, index, self) {});
·ele代表循环的当前项
·index代表当前项的下标
·self代表被循环的原数组对象

findIndex用法与find一样,只是它会返回第一个符合条件的元素下标位置,回调函数同样拥有三个参数,用法与find相同,这里就不做介绍了。

3.fill()方法

数组的一个填充方法,接受三个参数,分别代表填充所用元素,填充起始位置,填充结束位置(填充时不包含此位置)。

[1, 2, 3].fill('听风是风', 1, 2); //[1,'听风是风',3]
new Array(3).fill('echo'); //['echo','echo','echo']

前面我们有使用Array.from方法快速生成包含10个1的数组,那么到这里,你又知道了可以使用fill快速生成相同元素的数组。

需要注意的是,当我们使用fill填充的元素是对象时,会存在浅拷贝的问题,也就是说,当你填充后修改数组任意下标的对象,其它下标的元素都会改变

let arr = new Array(3).fill({
name: 'echo'
});
arr[0].name = '听风是风';
arr //[{name:'听风是风'},{name:'听风是风'},{name:'听风是风'}]

4.keys(),value()与entries()方法

这三个方法均用于遍历数组,这三个都返回一个遍历器对象,可以结合for...of循环分别对数组键名(keys()),数组键值(value()),数组键值对(entries())进行遍历。

let arr = [{name:'听风是风'},{age:26},{address:'深圳'}];
for(let index of arr.keys()){
console.log(index);//0,1,2
};
for(let ele of arr.values()){
console.log(ele);//{name:'听风是风'},{age:26},{address:'深圳'}
};
for(let [index,value] of arr.entries()){
console.log(index,value);//0 {name:'听风是风'},1 {age:26},2 {address:'深圳'}
};

请仔细看这个例子,我原以为keys遍历的是数组元素的name,age,adress,values遍历出来的是听风是风,26与深圳,其实并不是。

不要被方法名骗了,keys遍历仅仅是数组的下标,values遍历出来的是单个元素,entries遍历出来的是下标与元素的对。

如果不使用for...of循环,可以使用遍历器对象next方法进行遍历,由于我还没看这一章对next不太了解,这里先做个记录。

let arr = ['a','b','c'];
let index = arr.keys();
console.log(index.next().value);//
console.log(index.next().value);//
console.log(index.next().value);//

5.includes方法

此方法用于判断数组是否包含某个值,返回一个Boolean值,包含返回true,不包含则返回false。

let arr = [1,2,3];
//ES6
arr.includes(1);//true
//ES5 使用indexOf,并判断返回的索引是否大于-1
arr.indexOf(1)//

在这个方法之前我们习惯使用indexOf查找,找到指定元素返回该元素索引,找不到返回-1。但需要注意的是,indexOf无法查找NaN这个特例:

let arr = [NaN];
arr.includes(NaN);//true
arr.indexOf(NaN)//-1

我们也可以使用some方法自己模拟查找方法,

let contains = (() =>
Array.prototype.includes
? (arr, value) => arr.includes(value)
: (arr, value) => arr.some(el => el === value)
)();

6.数组的flat()与flatMap()方法

flat方法可以将多维数组转变为一维数组并返回一个新数组,不会修改原数组,也是非常的骚操作了:

let arr = [1, 2, 3, [4]];
arr.flat(); //[1,2,3,4]

那么要是数组维度超过2层怎么办呢,flat方法接受一个参数,定义该方法要降维的层数:

let arr = [1, 2, 3, [4,[5]]];
arr.flat(2); //[1,2,3,4,5]

如果你不想知道数组嵌套了多少层,不知道这个参数定义多少,你可以直接使用infinite代替,这样不管几层都会被降为一维数组:

let arr = [1,[2,[3,[4,[5]]]]];
arr.flat(Infinity); //[1,2,3,4,5]

flatMap()方法对数组中每个元素执行一个回调函数(类似map方法),然后使用返回值组成一个新数组,不会修改原数组,最后再对这个新数组执行flat方法。

需要注意的是flatMap方法最多只能展开二维数组:

let arr = [1, [2, [3, [4, [5]]]]];
let arr1 = [1, 2, 3, [4]];
//超过二维就无法解析了
let arr_ = arr.flatMap(ele => ele * 2); //[1,2,3,4,5]
//二维数组还是可以正常计算
let arr1_ = arr1.flatMap(ele => ele * 2); //[1,2,3,4,5]
console.log(arr_); //[2,NaN]
console.log(arr1_); //[2,4,6,8] //返回的新数组确实还会被flat方法降维一次
let arr3 = [1, 2, 3];
let arr3_ = arr3.flatMap(ele => [ele * 2]);
console.log(arr3_); //[2,4,6]

flatMap回调函数同样接受三个参数,与前面find方法参数意义相同。

es6入门6--数组拓展运算符,Array.from()基本用法的更多相关文章

  1. es6函数的rest参数和拓展运算符(...)的解析

    es6的新特性对函数的功能新增加了rest参数和...的拓展运算符.这是两个什么东西呢? 先来看一个问题:如何获取一个函数除了定义的参数之外的其他参数?传统的做法是借助函数的arguments关键字来 ...

  2. es6入门3--箭头函数与形参等属性的拓展

    对函数拓展兴趣更大一点,优先看,前面字符串后面再说,那些API居多,会使用能记住部分就好. 一.函数参数可以使用默认值 1.默认值生效条件 在变量的解构赋值就提到了,函数参数可以使用默认值了.正常我们 ...

  3. ES6数组的扩展--Array.from()和Array.of()

    一. Array.from() : 将伪数组对象或可遍历对象转换为真数组 1.何为伪数组 如果一个对象的所有键名都是正整数或零,并且有length属性,那么这个对象就很像数组,语法上称为"类 ...

  4. 【转】es6的拓展运算符 spread ...

    原文:https://blog.csdn.net/qq_30100043/article/details/53391308 The rest parameter syntax allows us to ...

  5. ES6的数组方法之Array.from

    首先说说什么是数组:数组在类型划分上归为Object,属于比较特殊的对象,数组的索引值类似于对象的key值. 数组的几个注意点: 1.数组的长度是可读属性,不可更改,数组的长度根据索引最大值. 2.数 ...

  6. ES6数组扩展运算符

    1 扩展运算符的运用 (1)复制数组 数组是复合的数据类型,直接复制的话,只是复制了指向底层数据机构的指针,而不是克隆一个全新的数组; const a1=[1,2]; const a2= a1; a2 ...

  7. 三、ES6中数组拓展

    一.Array.of() 将参数中所有值作为元素形成数组: console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] 参数的值可以为不同的类型: conso ...

  8. JavaScript入门之数组:Array类型详解

    数组应该是每个语言中都用得极度频繁的数据类型,JavaScript也不例外. 个人认为,Js中的Array类型非常强大. 首先没有C/C++等语言需要在数组初始化时指定数组长度(并不可变)的要求. 也 ...

  9. Shell - 简明Shell入门07 - 数组(Array)

    示例脚本及注释 #!/bin/bash test0=() # 定义数组 test1=(a b c d e f) # 定义数组 test2=( # 定义数组 'A?' "BB!" C ...

随机推荐

  1. postfix 邮件中继配置

    Postfix 配置邮件中继 A 邮件发送服务器B 邮件中继服务器 A. 配置发件服务器 # 开启转发规则 [root@Postfix ~]# vi /etc/postfix/main.cf tran ...

  2. Escaping Closures 两点:本质是生命周期标示符

    1.block需要(拷贝)保存: 2.block引用的环境变量需要处理. 相当于oc中的copy block. Escaping Closures A closure is said to escap ...

  3. .net core里用ZXing生成二维码

    先获取Nuget包 static void Main(string[] args) { string content = "二维码信息"; BitMatrix byteMatrix ...

  4. Perl Connect to Database without password as sysdba

    #!/oracle/product/11g/db/perl/bin/perl use lib '/oracle/product/11g/db/perl/lib/site_perl/5.10.0'; u ...

  5. Codevs P1017 乘积最大

    P1017 乘积最大 题目描述 Description 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的 ...

  6. uva 1585 Score(Uva-1585)

    vj:https://vjudge.net/problem/UVA-1585 不多说水题一个o一直加x就加的变为0 我的代码 #include <iostream> #include &l ...

  7. Myeclipse学习总结(1)——Myeclipse优化配置

    作为企业级开发最流行的工具,用Myeclipse开发java web程序无疑是最合适的,java web前端采用jsp来显示,myeclipse默认打开jsp的视图有卡顿的现象,那么如何更改jsp默认 ...

  8. python正则匹配——中文字符的匹配

    # -*- coding:utf-8 -*- import re '''python 3.5版本 正则匹配中文,固定形式:\u4E00-\u9FA5 ''' words = 'study in 山海大 ...

  9. HTMLParser in python

    You can know form the name that the HTMLParser is something used to parse HTML files.  In python, th ...

  10. springMvc--接受日期类型参数处理

    这个问题,也即是springMvc如何进行参数类型的转换 , 以把client传过来一个String类型,转换为日期类型为例 步骤 1.controller /** * 接收日期类型参数 * 注意: ...