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);     //0

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

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;
  }
};

原文地址:https://www.cnblogs.com/strick/p/10172721.html

时间: 2024-08-11 03:55:20

ES6躬行记(2)——扩展运算符和剩余参数的相关文章

ES6躬行记(16)——Set

ES6引入了两种新的数据结构:Set和Map.Set是一组值的集合,其中值不能重复:Map(也叫字典)是一组键值对的集合,其中键不能重复.Set和Map都由哈希表(Hash Table)实现,并可按添加时候的顺序枚举. 一.Set Set类似于Array(数组),但需要通过SameValueZero算法保持值的唯一性.在前面的第11篇中,曾讲到Object.is()依据的比较算法是SameValue,SameValueZero算法与之类似,唯一的区别就是在该算法中,+0和-0是相等的. 1)创建

ES6躬行记(7)——代码模块化

在ES6之前,由于ECMAScript不具备模块化管理的能力,因此往往需要借助第三方类库(例如遵守AMD规范的RequireJS或遵循CMD规范的SeaJS等)才能实现模块加载.而自从ES6引入了模块化标准后,就不需要再特地加载一次外部脚本了.模块化的语法不仅让JavaScript代码的组织变得更有条理,还包含封装.按需导出或导入等实用功能,可轻松应对日益复杂和庞大的前端工程.但有一点要注意,模块中的代码默认运行在严格模式中. 一.导出 一个模块就是一个独立的JavaScript文件,如果要读取

ES6躬行记(8)——数字

一.进制 ES6不仅完善了数字的八进制形式,还补充了一种十六进制形式,并且添加了全新的二进制形式.下面的三个变量分别表示八进制.十六进制和二进制的10,注释中给出了该进制的另一种写法. var octal = 0o12, //或0O12 hex = 0xa, //或0XA binary = 0b1010; //或0B1010 注意,只有十进制才能表示小数. 二.Number ES6不仅增强了Number对象处理数字的精度,还扩展了它的数字运算能力,新增的属性和方法如表2所示. 表2  Numbe

ES6躬行记(17)——Map

一.Map Map类似于Object(对象),可用来存储键值对,但需要通过SameValueZero算法保持键的唯一性.与Set一样,在使用之前也得要实例化,如下代码所示,构造函数Map()中的参数也是一个可选的可迭代对象,但此对象得是键值对的集合或两列的二维数组. new Map(); //Map(0) {} new Map([["name", "strick"], ["age", 28]]); //Map(2) {"name&quo

ES6的扩展运算符和rest参数

1.扩展运算符(spread)是三个点(...).它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列. 比如 var list=['大家好']: list.length=1.list[0]=大家好: var list2=[...'大家好']: list2.length = 3:list2[0]=大:list2[1]=家:list2[2]=好: 扩展运算符最有用之一是:Math.max(...arr);比较数组中的最大值. 2.rest参数 rest参数(形式为"...变量名"

TypeScript躬行记(3)——类

类是对对象的抽象,描述了对象的特征和行为,而对象就是类的实例.ES6引入了类的概念(相关内容可参考ES类和ES6类的继承两节),TypeScript在此基础上,不仅根据ES7等规范完善了类的语法,还添加了许多其它语法.而在使用TypeScript的类时,不必关心兼容性问题,因为这些工作已由编译器完成. 下面是一个简单的类,包含3个成员:带private修饰符的name属性.构造函数constructor()和getName()方法,最后一句使用new运算符创建了Person类的实例,并调用了一次

CSS躬行记(1)——CSS基础拾遗

一.box-decoration-break CSS3新增的box-decoration-break属性可指定行内非替换元素在跨行.跨列或跨页时的样式渲染,它包含两个值: (1)slice:默认值,盒子会被分割成多部分. (2)clone:断开的各个盒子会单独渲染. 下面用一个示例来演示两种的区别,第一个span元素采用box-decoration-break的默认值,效果如第一张图所示,在断行处没有左右内边距和圆角:第二个span元素box-decoration-break的值为clone,效

CSS躬行记(2)——伪类和伪元素

一.伪类选择器 伪选择器弥补了常规选择器的不足,能够实现一些特殊情况下的样式,例如在鼠标悬停时或只给字符串中的第一个字符指定样式.与类选择器类似,可以从HTML元素的class属性中查看到,但伪选择器不会出现在HTML文档中(有几个例外,如:lang.::placeholder等).并且它的关键字大小写不敏感,也就是说empty和EMPTY完全相同.伪选择器分为两种:伪类选择器和伪元素选择器.注意,伪选择器会以一个或两个冒号(:)开头,并且如果要与其它选择器组合使用,那么只能与类型选择器(即元素

React躬行记(5)——React和DOM

React实现了一套与浏览器无关的DOM系统,包括元素渲染.节点查询.事件处理等机制. 一.ReactDOM 自React v0.14开始,官方将与DOM相关的操作从React中剥离,组成单独的react-dom库,从而让React能兼容更多的终端.在引入react-dom库后,就能调用一个全局对象:ReactDOM,虽然在之前的章节中已多次使用该对象,但是都没有给出过多的讲解,本节将对其做重点分析. ReactDOM只包含了unmountComponentAtNode().findDOMNod