ES6躬行记(2)——扩展运算符和剩余参数

  扩展运算符(Spread Operator)和剩余参数(Rest Parameter)的写法相同,都是在变量或字面量以前加三个点(...),而且只能用于包含Symbol.iterator属性的可迭代对象(iterable)。虽然二者之间有诸多相似,但它们的功能和应用场景却彻底不一样。扩展运算符能把总体展开成个体,经常使用于函数调用、数组或字符串处理等;而剩余参数正好相反,把个体合并成总体,经常使用于函数声明、解构参数等。此处的总体多是数组、字符串或类数组对象等,个体多是字符、数组的元素或函数的参数等。html

1、扩展运算符

  扩展运算符的用途简单归纳,能够分为如下三种。数组

(1)替代函数的apply()方法。app

(2)简化函数调用时传递实参的方式。dom

(3)处理数组和字符串。函数

1)apply()this

  函数的apply()方法可以间接调用其它对象的方法,每每能收获奇效,例如用Math对象的min()方法获取数组中的最小值,min()方法原本只接收一组参数,利用apply()方法后就能直接传递一个数组,以下所示。spa

let arr = [1, 0, 2],
  min;
min = Math.min(1, 0, 2);                 //一组参数的调用方式
min = Math.min.apply(undefined, arr);    //利用apply()间接调用

  虽然apply()方法很便捷,但每次都必须设置this的指向(即定义第一个参数),而且迂回的写法可能会为理解代码意图设置障碍。而使用扩展运算符后,既能以简单的语法形式完成相同的功能,还能更清晰的代表代码的意图。下面用扩展运算符查找数组中的最小值。rest

min = Math.min(...arr);
console.log(min);     //0

2)传参code

  函数在被调用时,实参一般都是以逗号分隔的序列形式传递到函数体内。若是实参的值被保存在数组中,那么就要一个一个的读取数组中指定位置的元素,例如建立一个日期对象(调用它的构造函数),把年月日的信息保存在数组中,以下代码所示。注释中的日期并非默认的显示格式,只是为了更容易阅读而这么写的。htm

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"]

2、剩余参数

  在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;
  }
};
相关文章
相关标签/搜索