ES6躬行记(2)——扩展运算符和剩余参数
扩展运算符(Spread Operator)和剩余参数(Rest Parameter)的写法相同,都是在变量或字面量之前加三个点(...),并且只能用于包含Symbol.iterator属性的可迭代对象(iterable)。虽然两者之间有诸多类似,但它们的功能和应用场景却完全不同。扩展运算符能把整体展开成个体,常用于函数调用、数组或字符串处理等;而剩余参数正好相反,把个体合并成整体,常用于函数声明、解构参数等。此处的整体可能是数组、字符串或类数组对象等,个体可能是字符、数组的元素或函数的参数等。
一、扩展运算符
扩展运算符的用途简单概括,可以分为以下三种。
(1)替代函数的apply()方法。
(2)简化函数调用时传递实参的方式。
(3)处理数组和字符串。
1)apply()
函数的apply()方法能够间接调用其它对象的方法,往往能收获奇效,例如用Math对象的min()方法获取数组中的最小值,min()方法本来只接收一组参数,利用apply()方法后就能直接传递一个数组,如下所示。
let arr = [1, 0, 2],
min;
min = Math.min(1, 0, 2); //一组参数的调用方式
min = Math.min.apply(undefined, arr); //利用apply()间接调用
虽然apply()方法很便捷,但每次都必须设置this的指向(即定义第一个参数),并且迂回的写法可能会为理解代码意图设置障碍。而使用扩展运算符后,既能以简单的语法形式完成相同的功能,还能更清晰的表明代码的意图。下面用扩展运算符查找数组中的最小值。
min = Math.min(...arr);
console.log(min); //
2)传参
函数在被调用时,实参通常都是以逗号分隔的序列形式传递到函数体内。如果实参的值被保存在数组中,那么就要一个一个的读取数组中指定位置的元素,例如创建一个日期对象(调用它的构造函数),把年月日的信息保存在数组中,如下代码所示。注释中的日期并不是默认的显示格式,只是为了更容易阅读而这么写的。
let date = [2018, 6, 9];
new Date(date[0], date[1], date[2]); //2018-7-6
换成扩展运算符的写法后,实参的传递就变得非常的简洁,如下所示。
new Date(...date); //2018-7-6
不仅如此,在调用函数的时候,还可以使用多个扩展运算符,并能和普通的实参混合使用,如下所示。
let time = [10, 28];
new Date(...date, ...time, 45); //2018-7-6 10:28:45
3)数组和字符串
在扩展运算符出现之前,要执行数组的复制、合并等操作,需要调用数组的slice()、concat()、unshift()等方法。这些方法到底是单独调用还是组合调用,由实际情况而定。下面是一个数组复制与合并的简单示例。
let arr1 = [1, 2, 3],
arr2,
arr3;
arr2 = arr1.slice(); //复制数组
arr3 = arr2.concat(arr1); //合并数组
console.log(arr1); //[1, 2, 3]
console.log(arr2); //[1, 2, 3]
console.log(arr3); //[1, 2, 3, 1, 2, 3]
接下来用扩展运算符来完成同样的功能,如下代码所示。
arr2 = [...arr1]; //复制数组
arr3 = [...arr1, ...arr2]; //合并数组
在实际项目中,肯定会碰到各式各样的数组操作,合理利用扩展运算符,不但可以节省大量的代码,还能提升代码的可读性。
扩展运算符不仅能处理数组,还能处理字符串。在JavaScript中,字符串的行为类似于数组,但它不能直接调用数组的方法,需要先执行自己的split()方法转换成数组。而使用扩展运算符后,就能省去这步操作,具体如下所示,注意,包裹的方括号不能省略。
let str = "strick";
str.split(""); //["s", "t", "r", "i", "c", "k"]
[...str]; //["s", "t", "r", "i", "c", "k"]
二、剩余参数
在JavaScript的函数中,声明时定义的形参个数可以和传入的实参个数不同。当实参个数大于形参个数时,ES6新增的剩余参数能把没有对应形参的实参收集到一个数组中。下面是一个简单的示例。
function func(name, ...args) {
console.log(name);
console.log(args[0]);
}
func("strick"); //首先输出"strick",然后输出undefined
func("freedom", 29); //首先输出"freedom",然后输出29
第一次调用func()函数只传入了一个实参,对应的形参就是name。第二次调用func()函数传入了两个实参,第一个有对应的形参,而第二个并没有对应的形参。此时,该实参就会被放到数组args(就是剩余参数)中,变为该数组的一个元素,在函数体内就能通过数组的索引读取该实参。有一点要注意,剩余参数不会影响函数的length属性,该属性的值表示形参个数。以上面的func()函数为例,... args并不是一个形参,因此,func()函数的length属性值为1。
console.log(func.length); //
1)解构
剩余参数可以被解构(将在第3篇中讲解),这意味着剩余参数中的元素可以被赋给函数体中的同名变量,如下所示。
function destructuring (name, ...[age]) {
console.log(name);
console.log(age);
}
destructuring ("jane", 28); //首先输出"jane",然后输出28
引入剩余参数就是为了能替代函数内部的arguments,它是一个类数组对象,管理着实参列表,该列表包含了传入到函数内的所有实参。由于arguments对象不具备数组的方法,所以很多时候在使用之前要先转换成一个数组。而剩余参数本来就是一个数组,避免了这多余的一步,使用起来既优雅又自然。
2)两点限制
剩余参数有两点限制,在使用时需要引起注意。第一点是在函数中声明时必须放在最后,下面是一种错误的写法。
function restrict1(...args, name) {
//抛出语法错误
}
第二点是不能在对象字面量的setter方法中声明,因为该方法只接收一个参数,而剩余参数不会限制参数的数量。注意,setter方法在定义时会用set替代function关键字,下面是一个会抛出语法错误的例子。
var obj = {
set age(...value) {
this._age = value;
}
};
ES6躬行记(2)——扩展运算符和剩余参数的更多相关文章
- ES6躬行记(1)——let和const
古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...
- ES6躬行记 笔记
ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向
- ES6躬行记(3)——解构
解构(destructuring)是一种赋值语法,可从数组中提取元素或从对象中提取属性,将其值赋给对应的变量或另一个对象的属性.解构地目的是简化提取数据的过程,增强代码的可读性.有两种解构语法,分别是 ...
- ES6躬行记(19)——生成器
根据ES6制订的标准自定义迭代器实现起来比较复杂,因此ES6又引入了生成器的概念,生成器(Generator)是一个能直接创建并返回迭代器的特殊函数,可将其赋给可迭代对象的Symbol.iterato ...
- ES6躬行记(18)——迭代器
ES6将迭代器和生成器内置到语言中,不仅简化了数据处理和集合操作,还弥补了for.while等普通循环的不足,例如难以遍历无穷集合或自定义的树结构等. 迭代器(Iterator)是一种用于迭代的对象, ...
- ES6躬行记(16)——Set
ES6引入了两种新的数据结构:Set和Map.Set是一组值的集合,其中值不能重复:Map(也叫字典)是一组键值对的集合,其中键不能重复.Set和Map都由哈希表(Hash Table)实现,并可按添 ...
- ES6躬行记(12)——数组
ES6为数组添加了多个新方法,既对它的功能进行了强化,也消除了容易产生歧义的语法. 一.静态方法 1)of() ES6为Array对象新增的第一个静态方法是of(),用于创建数组,它能接收任意个参数, ...
- ES6躬行记(15)——箭头函数和尾调用优化
一.箭头函数 箭头函数(Arrow Function)是ES6提供的一个很实用的新功能,与普通函数相比,不但在语法上更为简洁,而且在使用时也有更多注意点,下面列出了其中的三点: (1)由于不能作为构造 ...
- ES6躬行记(14)——函数
在前面的章节中,已陆陆续续介绍了ES6为改良函数而引入的几个新特性,本章将会继续讲解ES6对函数的其余改进,包括默认参数.元属性.块级函数和箭头函数等. 一.默认参数 在ES5时代,只能在函数体中定义 ...
随机推荐
- inet_pton, inet_ntop
Linux下这2个IP地址转换函数,可以在将IP地址在“点分十进制”和“整数”之间转换而且,inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6.算是比较新的函数了. inet_ ...
- Python基础环境搭建
一.编程语言 1.解释型语言:每执行一次程序就要将代码翻译一次,如Java.JavaScript.VBScript.Perl.Python.Ruby.MATLAB 等都是解释型语言 2.编译型语言:程 ...
- html文件上传保存-(.html and string translate into .html )
//上传h5编辑器编辑的html内容 uploadHtml(newsId?: any) { const news = newsId !== undefined ? newsId : 'new'; le ...
- 0x66 Tarjan算法与无向图连通性(1)
……是什么? 给定无向连通图G=(V,E)(不一定连通); 割点:若对于x∈V,从图中删去节点x以及所有与x关联的边后,G分裂成两个或两个以上不相连的子图,则称x为G的割点. 桥(割边):若对于e∈E ...
- retrofit+rxjava封装
public class RetrofitHelper { private static OkHttpClient okHttpClient; private static ServiceAPI se ...
- 关于CSS层叠机制
谈到层叠机制,首先我们要知道什么是声明冲突. 声明冲突有三个条件:①多个选择器选中同一个元素:②声明块里的属性相同:③属性的属性值不同.同时满足这三点时就会产生声明冲突.比如下图html代码: < ...
- Collection类,泛型
Collection(接口) 所有超级接口: Iterable<E> 一.集合 1.集合的介绍&集合和数组的区别 什么是集合:java中的一种容器 什么是数组:java中的一种容器 ...
- VS code的疑惑之处
作为一个新手,我充满疑惑 eg:下载了git但无法使用匹配 然后在各位博主的详细解释下知道 VS code更新后的git.path被格式化了: so需要进行路径覆盖. 在这之后我的终端依旧出现问题 ...
- Java并发编程实战
代码中比较容易出现bug的场景: 不一致的同步,直接调用Thread.run,未被释放的锁,空的同步块,双重检查加锁,在构造函数中启动一个线程,notify或notifyAll通知错误,Object. ...
- cef3:禁止win10高dpi下cef对内部网页进行缩放
1.使用命令行参数 //禁止cef进行dpi缩放 command_line->AppendSwitchWithValue("--force-device-scale-factor&qu ...