Javascript Rest参数和拓展操作实例讲解
javascript的许多内置函数都支持任意数量的参数,比如math.max(arg1, arg2, ..., argn),object.assign(dest, src1, ..., srcn)等等
rest参数“...”
一个函数可以被任意个参数调用,例如:
function sum(a, b) { return a + b; } alert( sum(1, 2, 3, 4, 5) );
使用多个参数来调用函数并不会报错,当然只有前面两个参数会被使用。在javascript里我们可以使用rest参数来定义不确认个数的参数,即使用三个点“...”,它表示将多余的参数接受并放到一个数组里,例如:
function sumall(...args) { // args is the name for the array let sum = 0; for (let arg of args) sum += arg; return sum; } alert( sumall(1) ); // 1 alert( sumall(1, 2) ); // 3 alert( sumall(1, 2, 3) ); // 6
我们也可以指定确定参数个数,例如:
function showname(firstname, lastname, ...titles) { alert( firstname + ' ' + lastname ); // julius caesar // the rest go into titles array // i.e. titles = ["consul", "imperator"] alert( titles[0] ); // consul alert( titles[1] ); // imperator alert( titles.length ); // 2 } showname("julius", "caesar", "consul", "imperator");
需要注意的是rest参数必须放在参数列表的最后面,否则会报错误,例如:
function f(arg1, ...rest, arg2) { // arg2 after ...rest ?! // error }
“arguments”参数变量
javascript的函数都有一个默认的参数变量arguments,它包含函数所有的参数变量,例如:
function showname() { alert( arguments.length ); alert( arguments[0] ); alert( arguments[1] ); // it's iterable // for(let arg of arguments) alert(arg); } // shows: 2, julius, caesar showname("julius", "caesar"); // shows: 1, ilya, undefined (no second argument) showname("ilya");
在rest参数没出现的时候,javascript是使用arguments参数来获取所有的参数,由于历史原因它被保留至今。与rest参数不同的是,arguments参数是类数组和可迭代的,而不是真正的数组,故不能使用arguments.map(...)
箭头函数没有arguments
需要注意的是,箭头函数是没有arguments参数的,当我们访问箭头函数的arguments时,它默认使用外部函数的arguments,例如:
function f() { let showarg = () => alert(arguments[0]); showarg(); } f(1); // 1在前面我们已经知道剪头函数没有this,而且它的this是使用外部函数的this,在这里,arguments也是一样一样的~
拓展操作
前面我们已经知道如何从参数列表里获取一个数组,当有时候我们需要做的事情却是相反的,例如下面这个例子:
alert( math.max(3, 5, 1) ); // 5 let arr = [3, 5, 1]; alert( math.max(arr) ); // nan
math.max()对指定参数是正常运作的,但对于数组参数则发生错误,这是因为math.max()接受的是参数列表,而不是一个数组。
为了解决这个问题,拓展操作就被引入进来了,看下面这个例子:
let arr = [3, 5, 1]; alert( math.max(...arr) ); // 5 (spread turns array into a list of arguments)
这里的...arr就是拓展操作,只要参数是可迭代的,就可以使用拓展操作,例如array,string等等
我们也可以传递多个拓展操作参数,例如:
let arr1 = [1, -2, 3, 4]; let arr2 = [8, 3, -8, 1]; alert( math.max(...arr1, ...arr2) ); // 8
也可以跟普通参数组合,例如:
let arr1 = [1, -2, 3, 4]; let arr2 = [8, 3, -8, 1]; alert( math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
对于数组合并函数也是一样,例如:
let arr = [3, 5, 1]; let arr2 = [8, 9, 15]; let merged = [0, ...arr, 2, ...arr2]; alert(merged); // 0,3,5,1,2,8,9,15 (0, then arr, then 2, then arr2)
其实拓展操作的原理是将参数进行迭代并逐一返回该值,类似于for...of,这也是为什么拓展操作要求参数必须为可迭代,例如对string进行拓展操作:
let str = "hello"; alert( [...str] ); // h,e,l,l,o
..str操作后返回“h,e,l,l,o”,再将返回的内容放入数组中
在前面我们学习了array.from()这个方法,我们也可以用它来转换字符串为数组,与上面例子的结果一样,如下:
let str = "hello"; // array.from converts an iterable into an array alert( array.from(str) ); // h,e,l,l,o
但是这里array.from()和拓展操作还是有细微的区别的:
(1)array.from()支持可迭代对象和类数组对象;
(2)拓展操作只支持可迭代对象;
对于将对象转换为数组,array.from()一般使用得更多