不只人类世界,就连编程的世界里也是分三六九等的,呐,函数就是编程世界里的第一等公民。
函数的内容比较多,所以我们分成两篇笔记,本篇主要介绍函数参数相关:参数默认值和无命名参数
参数默认值
- 函数形参的默认值
在ES5中,我们有的时候也需要改参数设置一个默认值,做法一般如下:
function defaultParams( arg1, arg2, callback ){
arg2 = arg2 || 100;
callback = callback ||function(){};
console.log(arg1); // undefined
console.log(arg2); //100
console.log(callback); //function(){};
}
defaultParams();
* 当我们调用函数时,不传入参数,没有设置默认值的参数,其值为undefined;
* 设置默认值的时候,参数的值为所设置的默认值;
但是,这里有一个隐藏的彩蛋(bug),就是假设arg2我们传入一个数字0时,arg2的参数值会变成100,
0虽然是合法值,但是逻辑运算却是false...
可以将代码修改为arg2 =(typeof arg2!=='undefined') || 100;
这种方法解决了bug,但是却比较繁琐,不符合我们这些有洁癖程序员的习惯...
那么我们现在来看看,ES6中是如何优雅的解决这个问题的~
看ES6的代码:
function defaultParams( arg1, arg2=100, callback=function(){} ){
console.log(arg1); // undefined
console.log(arg2); //100
console.log(callback); //function(){};
}
defaultParams();
怎么样?简洁吧~简直完美!
只需要在定义参数的时候用“=”进行赋值即可。
如果在调用的时候,有传入形参,则为传入的值,如果没有传入,则为“=”右侧所定义的值。
声明函数时,可以喂任意参数指定默认值,在已指定默认值的参数后可以继续声明无默认值参数
- 默认参数值对arguments对象的影响
首先,在ES5的非严格模式下,函数命名参数的变化会影响arguments的表现,具体看代码:
//ES5非严格模式
function defaultParamsWithArgs( first, second ){
console.log( first === arguments[0] ); // true
console.log( second === arguments[1] ); // true
first = 1;
second = 2;
console.log( first === arguments[0] ); // true
console.log( second === arguments[1] ); // true
};
defaultParamsWithArgs("a","b");
* 在ES5的非严格模式下,函数体内部对参数值的改变,会同步更新到arguments对象中,
也就是说你无法断定参数的初始值是什么样的。
在ES5中的严格模式或是ES6中,修改了arguments的这个令人困惑的行为,也就是说无论参数在函数体内做何种变化,arguments只受参数传递进来的初始值影响。
让我们来看代码:
// ES5 严格模式
function defaultParamsWithStrict( first, second ){
"use strict";
console.log( first === arguments[0] ); // true
console.log( second === arguments[1] ); // true
first = 1;
second = 2;
console.log( first === arguments[0] ); // false
console.log( second === arguments[1] ); // false
}
defaultParamsWithStrict("a","b");
* 在ES5的严格模式下,在函数体内修改了形参first, second的值,但是修改后的值和arguments不再一致了,
这里的arguments仍是函数在调用的时候传进来“a”,“b”。
// ES6 不论是否为严格模式,都和ES5的严格模式保持一致
function defaultParamsWithES6( first, second=3){
console.log(arguments.length); // 1
console.log( first === arguments[0] ); // true
console.log( second === arguments[1] ); // false
first = 1;
second = 2;
console.log( first === arguments[0] ); // false
console.log( second === arguments[1] ); // false
}
defaultParamsWithES6('a');
* 在调用defaultParamsWithES6函数时,我们只传入了一个参数first=》“a”,
second我们设置了默认参数3,并且又在函数体内将其修改为了2,
但是你会发现,我们运行的结果arguments的length属性值为1,并且只有first的值和arguments[0]的值全等。
这就是ES6中对arguments做的修改,arguments在任何时候只受函数调用时传入的参数初始值影响,
函数的参数默认值和在函数体内对参数做的修改,都不会改变arguments的初始状态。
- 默认参数表达式
有了参数默认值,我们就可以做很多有趣的事情了。
参数不但可以使用默认值,还可以使用默认表达式(函数)。
话不多说,上菜(看代码~):
function defaultValue(){
return 5;
}
function add( first, second=defaultValue()){
return first + second;
}
console.log( add(1,1) ); //2
// *当我们传递两个参数时,second设置的默认表达式就被覆盖了,此时结果是1+1=2
console.log( add(1) ); //6
// *当我们只传递一个参数的时候,second调用默认表达式,即函数defaultValue()运行的结果 5,结果是1+5=6
注意,这里设置默认表达式时,函数是有调用的()小括号的,有小括号的时候我们的得到的是默认表达式运行以后的返回值,没有这个括号的时候,我们得到的是对函数的引用,意义是不一样的~
由于默认表达式只有在调用的时候才会解析,所以我们还可以使用先定义得到参数作为后定义参数的默认值:
function defaultValue(value){
return value;
}
function add( first, second=defaultValue(first)){
return first + second;
}
console.log( add(2,2) ); //4
console.log( add(2) ); //4
在引用参数默认值的时候,值允许引用前面的参数的值,即先定义的参数不能访问后定义的参数,否则会抛出错误,原因请参考临时死区
function defaultValue(value){
return value;
}
function add( first, second=defaultValue(first)){
return first + second;
}
console.log( add(2,2) ); //4
console.log( add(2) ); //4
说明:函数参数有自己的作用域和临时死区,其与函数体的作用域是个自己独立的,就是说参数的默认值不可访问函数体内声明的变量。
- 处理无命名参数
我们知道在JS中,无论函数定义了多少参数,在调用的时候都不限制实际传参的数量,但是很多时候我们未必能穷举所有的参数,不注明参数的话,可读性又比较差,ES6为此提供了不定参数解决这个问题。
语法:在函数的命名参数前添加三个点(...)就表明这是一个不定参数,该参数为一个数组,包含着自它之后传入的所有参数,通过这个数组名即可逐一访问里面的参数。
function checkArgs(param,...keys){
console.log(checkArgs.length); // 1
//函数的length属性只统计函数命名参数的数量,不定参数的加入不影响其值
console.log(arguments.length); // 3
// arguments 对象包含了所有传入的参数的个数
console.log(keys.length); //2
//不定参数的个数
console.log(keys) ; // ['a','b','c']
//不定参数的内容 是一个数组
console.log(keys[0],arguments[1]) //a a
// 不定参数 和 arguments的对应关系,假设没有param参数的传入,则是对应索引值
// 函数定义了不定参数时,在函数被调用时,arguments对象包含了所有传入的参数
console.log(keys[1],arguments[2]) //b b
}
checkArgs('a','b','c')
注意:不定参数有两条使用限制:1.每个函数最多只能声明一个不定参数,且只能放在所有命名参数的末尾;2.不定参数不能用于对象字面量setter之中,因为setter的参数有且只有一个,不定参数可以无限多,两个规则冲突则抛出错误。
网友评论