在js中,无论在函数定义中声明了多少形参,都可以传入任意数量的参数。当已定义的形参无对应传入实参时,可以为其指定默认值。
默认参数
// 当不为有默认值的参数传值或传入undefined的时候,会使用其默认值
function A(name, age = 8, nation) {}
默认参数对arguments对象的影响
在es5的非严格模式下,命名参数(实参有传递)的变化会同步更新到arguments对象中。但在严格模式下,无论参数如何变化,arguments对象不再随之改变。
function mixArgs(first,second){
console.log(arguments.length); //1
console.log(first == arguments[0]); //true
console.log(second); //undefined,没有传递值的命名参数自动赋值undefined
console.log(arguments[1]); //undefined,arguments是类数组,超出数组长度的下标值为undefined
console.log(second == arguments[1]); //true
first = 'c';
second = 'd';
console.log(first == arguments[0]); //true
console.log(second); //d
console.log(arguments[1]); //undefined
console.log(second == arguments[1]); //false
}
mixArgs('a');
function mixArgs(first,second){
'use strict';
console.log(arguments.length); //1
console.log(first == arguments[0]); //true
console.log(second == arguments[1]); //true
first = 'c';
second = 'd';
console.log(first == arguments[0]); //false
console.log(second == arguments[1]); //false
}
mixArgs('a');
在es6中,如果一个函数使用了默认参数值,其行为都和es5严格模式一致,也就是无论参数如何变化,arguments对象不再随之改变。
function mixArgs(first,second = 'b'){
// 'use strict'; //默认值与严格模式冲突了,如果在函数中使用严格模式,那么函数的参数就不能有默认值
console.log(arguments.length); //1
console.log(first == arguments[0]); //true
console.log(second == arguments[1]); //false
first = 'c';
second = 'd';
console.log(first == arguments[0]); //false
console.log(second == arguments[1]); //false
}
mixArgs('a');
默认参数表达式
默认参数的值不一定非要是一个常量,也可以通过函数执行的到默认参数的值。
function getValue() {return 5}
function add(first,second = getValue()) {return first + second}
由于默认参数是在函数调用的时候求值的,所以可以使用先定义的参数作为后定义参数的默认值。
function add(first,second = first) {return first + second}
但不可以在先定义的参数上访问后定义的参数,这是会报错的,因为此时后定义的参数正处于临时死区。
不定参数
由于js中形参和传入实参的个数没有限制,当形参个数 > 实参个数,我们可以使用默认参数来设置多余形参的默认值,当形参个数 < 实参个数,我们也可以使用不定参数。
// pick函数从传进来的对象中获取指定key的合集
function pick(object){
let result = Object.create(null);
for(let i =1,len = arguments.length;i<len;i++){
result[arguments[i]] = object[arguments[i]];
}
return result;
}
let book = {
title:"Understanding ECMAScript 6",
autor:"Nicholas C. Zakas",
year:2016
}
let bookData = pick(book,"autor","year")
但是上述代码会有两个问题:
- 单独看pick函数,只有一个参数,对于可以传入多个参数看起来不明朗
- 调用时传入了三个参数,只有第一个参数有命名形参,后面两个都是无命名参数,取的时候只能遍历arguments,且不是从下标0开始
为了解决这些问题,es6引入了不定参数,在命名参数前添加三个点(...),该参数为一个数组,包含自它之后传入的所有参数。
function pick(object,...keys){
let result = Object.create(null);
for(let i =0,len = keys.length;i<len;i++){
result[keys[i]] = object[keys[i]];
}
return result;
}
使用限制
- 一个函数最多只能声明一个不定参数,且一定要放在所有参数的末尾
- 不定参数不可以用在对象字面量setter中
增强的Function构造函数
es6中,Function构造函数也支持参数默认值和不定参数
new Function("first", "second=first", "return first+second")
new Function("...args", "return args[0]")
展开运算符
展开运算符可以让你指定一个数组,将它们打散后作为独立的参数传入函数。
//Math.max不支持传入数组,但支持传入多个参数
let num1 = Math.max(25,50,75,100);
let values = [25,50,75,100];
//apply可将数组解析成一个一个的参数列表
let num2 = Math.max.apply(Math,values);
//用apply不清晰,es6加入不定参数
let num3 = Math.max(...values);