『ES6脚丫系列』扩展运算符spread和rest参数数组
学习就比如是座大山,人们沿着不一样的路爬山,分享着本身看到的风景。你不必定能看到别人看到的风景,体会到别人的心情。只有本身去爬山,才能看到不同的风景,体会才更加深入。
【01】又叫作展开运算符。app
【02】spread 运算符和 rest 参数相反。函数
三个点: ...学习
将一个数组或一个可迭代的对象,在一次调用中,将它们的内容分隔为单个单个的成员参与运算。ui
若是是数组:this
等同于将一个数组去掉外层的方括号,而后总体放在原先的位置同样。
逗号分隔的参数列表。
若是是字符串:spa
等同于,变为单个字符单个字符用逗号分隔的参数列表。let res = [..."hel"];//["h","e","l"];prototype
若是是可迭代对象:(只有部署了iterator的对象才是可迭代的)rest
把属性变为用逗号分隔的参数列表。
例子:code
let array = ['one', 'two', 'three'] // These two are exactly the same console.log(...array) // one two three console.log('one', 'two', 'three') // one two three
例子:
var middle = [3, 4]; var arr = [1, 2, middle, 5, 6]; console.log(arr);// [1, 2, [3, 4], 5, 6]
只想要一个数组呢?
var middle = [3, 4]; var arr = [1, 2, ...middle, 5, 6]; console.log(arr);// [1, 2, 3, 4, 5, 6]
slice()是JS数组的一个方法,它能够复制数组,相似的,可使用扩展运算符来复制数组:
arr2并不等于arr。由于不是相等操做,它们引用的地址不同。
var arr = ['a', 'b', 'c']; var arr2 = [...arr]; console.log(arr2);// ['a', 'b', 'c']
可使用扩展运算符替代concat()来链接数组。
首先,咱们来看看concat()方法是如何实现的。
var arr = ['a', 'b', 'c']; var arr2 = ['d', 'e', 'f']; arr1 = arr.concat(arr2); console.log(arr);// ['a', 'b', 'c', 'd', 'e', 'f']
使用扩展运算符:
var arr = ['a', 'b', 'c']; var arr2 = ['d', 'e', 'f']; arr = [...arr, ...arr2]; console.log(arr);// ['a', 'b', 'c', 'd', 'e', 'f']
能够在使用math函数时结合扩展运算符。
例子。
Math.max()会返回一堆数字中最大的数。
Math.max();// -Infinity Math.max(1, 2, 3);// 3 Math.max(100, 3, 4);// 100
若是不使用扩展运算符,最简单的方式是使用.apply(),将一个数组做为参数传入Math.max()
var arr = [2, 4, 8, 6, 0]; function max(arr) { return Math.max.apply(null, arr); } console.log(max(arr));// 8
这样作很麻烦。
如今来看一下如何使用扩展运算符来获得相同的结果的。只须要两行代码:
var arr = [2, 4, 8, 6, 0]; var max = Math.max(...arr); console.log(max);// 8 let numbers = [9, 4, 7, 1]; Math.min(...numbers); // 1
使用扩展运算符将字符串转换成数组。
var str = "hello"; var chars = [...str]; console.log(chars); // ['h', 'e',' l',' l', 'o']
// Convert NodeList to Array let divsArray = [...document.querySelectorAll('div')]; // Convert Arguments to Array let argsArray = [...arguments];
下面的例子使得一个类数组对象符合迭代协议,并利用spread运算符将其转变为一个数组:
function iterator() { var index = 0; return { next: () => ({ // Conform to Iterator protocol done : index >= this.length, value: this[index++] }) }; } var arrayLike = { 0: 'Cat', 1: 'Bird', length: 2 }; arrayLike[Symbol.iterator] = iterator; //Conform to Iterable Protocol var array = [...arrayLike]; console.log(array); // => ['Cat', 'Bird']
【01】rest参数。用三个点表示。
【02】rest 参数意味着把剩下的东西包装成一个数组。
【03】用在函数参数和解构数组中。
它将一个逗号分隔的参数列表转换成一个数组。
吃码小妖:相似打包和解压的既视感?
若是在函数形参中使用了rest参数(打包),那么在函数中使用spread使用它(解压),等于原封不动的使用实参了。
【04】当三个点出如今函数参数时,它意味着将调用函数时的参数列表变为一个数组。该参数名就是这个数组。
若是函数参数自己就是一个数组,那么rest参数运算符等于把函数形参变为一个二维数组了。
例子:
function a(...args){} a(1,2,3,4,5);
等同于
function a(){ var args = [arguments[0],arguments[1],...,arguments[N]]; }; a(1,2,3,4,5);
【05】若是是多个形参,那么rest参数须要是参数列表中的最后一个参数。写成逗号分隔的参数列表。
arguments对象不具备这种选择性而且始终包含全部的参数值。
例子:
function filter(type, ...items) { return items.filter(item => typeof item === type); } filter('boolean', true, 0, false); // => [true, false] filter('number', false, 4, 'Welcome', 7); // => [4, 7]
【01】使用不定数量的函数参数。
在ES5中,当咱们须要处理一个未知数量的参数的函数时,可使用arguments变量。
function sum () { console.log(arguments) } sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//55
计算这个参数总和的一种方法是将其转换成具备 Array.prototype.slice.call(arguments) 的数组,而后用数组方法循环遍历每一个数字,如 forEach 或 reduce。
我相信你能够本身实现 forEach ,因此这里是 reduce 的例子:
// ES5 way function sum () { let argsArray = Array.prototype.slice.call(arguments); return argsArray.reduce(function(sum, current) { return sum + current; }, 0) }
使用 ES6 rest 参数,能够将全部逗号分隔的参数直接打包到数组中。
// ES6 way const sum = (...args) => args.reduce((sum, current) => sum + current, 0) // ES6 way if we didn't shortcut it with so many arrow functions function sum (...args) { return args.reduce((sum, current) => sum + current, 0) }
【】在数组解构中遇到三个点。它会将剩余的元素打包变为一个数组。
let scores = ['98', '95', '93', '90', '87', '85'] let [first, second, third] = scores console.log(first) // 98 console.log(second) // 95 console.log(third) // 93
若是咱们想要 rest 的分数,咱们能够经过将剩余的分数打包成一个数组。
let scores = ['98', '95', '93', '90', '87', '85'] let [first, second, third, ...restOfScores] = scores console.log(restOfScores) // [90, 97, 95]
用途2:在数组中插入不定数量的元素。
例如,.push(item1, ..., itemN)会把元素一个接一个的插入数组:不得不循环每一个元素将其做为参数。但这并不老是很方便:有时须要把一整个数组的元素push到目标数组。
在ES5中这能够经过.apply()作到:用一种不友好且繁琐的方式。让咱们看看:
var fruits = ['banana']; var moreFruits = ['apple', 'orange']; Array.prototype.push.apply(fruits, moreFruits); console.log(fruits); // => ['banana', 'apple', 'orange'] ES6:let res = fruits.push(...moreFruits);console.log(res);// ['banana', 'apple', 'orange']
【】如何更好的把数组中的元素做为参数填充到函数调用中。
ES5在函数对象上提供了 .apply()来解决这个问题。不幸的是这项技术有3个问题:
例子:
let countries = ['Moldova', 'Ukraine']; countries.push.apply(countries, ['USA', 'Japan']); console.log(countries); // => ['Moldova', 'Ukraine', 'USA', 'Japan']
例子:
function spreadReporter(...values) { let object = [...values]; return object[0].length; } var items = ['one', 'two', 'three']; console.log(spreadReporter(items)); // 3
例子:
let dairy = []; let store = { add: function(category, ...items) { category.push(...items); } }; store.add(dairy, 'milk', 'sour cream'); store.add(dairy, 'ice cream', 'yogurt', 'cheese'); console.log(dairy); // outputs ["milk", "sour cream", "ice cream", "yogurt", "cheese"]
在复杂情景中的函数体内操做arguments对象是很麻烦的。
为了在filterNumbers()访问sumOnlyNumbers()的arguments,你不得不建立一个临时变量args。这是由于filterNumbers()会定义它本身的arguments从而覆盖了外层的arguments。
这种方式能够工做,可是太繁琐了。
function sumOnlyNumbers() { function filterNumbers() { return Array.prototype.filter.call(args, element => typeof element === 'number'); } var args = arguments; var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); } sumOnlyNumbers(1, 'Hello', 5, false); // => 6
rest运算符能够优雅的解决这个问题。它容许你在函数声明时定义一个rest参数...args:
function sumOnlyNumbers(...args) { var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return args.filter(element => typeof element === 'number'); } } sumOnlyNumbers(1, 'Hello', 5, false); // => 6
函数声明function sumOnlyNumbers(...args)代表args以数组的形式接受调用参数。
【】箭头函数并不定义本身的arguments而是会访问外层做用域中的arguments对象。
例子:
(function() { let outerArguments = arguments; const concat = (...items) => { console.log(arguments === outerArguments); // => true return items.reduce((result, item) => result + item, ''); }; concat(1, 5, 'nine'); // => '15nine' })();
Spread运算符能够在构造器调用中使用数组元素做为参数,而这并不能经过直接使用.apply()作到。
让咱们看一个例子:
class King { constructor(name, country) { this.name = name; this.country = country; } getDescription() { return `${this.name} leads ${this.country}`; } } var details = ['Alexander the Great', 'Greece']; var Alexander = new King(...details); Alexander.getDescription(); // => 'Alexander the Great leads Greece'