参数分实参和虚参,定义函数时的参数叫虚参,调用函数时候传入参数的叫实参
本文主要小结一下平时编写代码时候遇到参数问题以及ES5、ES6中跟参数相关的语法
1.call和apply讲解
定义如下:
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
Function.apply(obj,args)
方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args--<arguments)
call:和apply的意思一样,只不过是参数列表不一样.
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
这里我们主要解决以下几个问题:
- apply和call的区别在哪里
- 什么情况下用apply,什么情况下用call
- apply的其他巧妙用法(一般在什么情况下可以使用apply)
看下面的例子
function Person(name,age){
this.name=name;
this.age=age
}
function Student(name,age,grade){
this.grade=grade;
Person.apply(this,arguments)
}
let studengtA=new Student('小A',10,'2年级')
console.log(studengtA);
输出结果是:大家懂得....
分析: Person.apply(this,arguments);
this:在创建对象在这个时候代表的是student
arguments:是一个数组,也就是[“小A”,”10”,”2年级”];
也就是通俗一点讲就是:执行一次Person,但其内部的this被apply改变了
2.扩展运算符(...)
在 ES5 中,apply() 方法可以很方便将数组作为参数传递给函数,经常用于使用 Math.max() 来取得数组的最大值。看下面的代码段:
//返回数组中的最大值
var myArray = [5, 10, 50];
Math.max(myArray); // Error: NaN
Math.max.apply(Math, myArray); // 50
Math.max() 方法不支持数组,只接受数字作为参数。当数组传递给函数,函数会抛出错误。但是当使用 apply() 方法后,数组变成了一个个单独的数组传递给了函数,所以 Math.max() 就能够正确的执行了。
幸运的是,ES6 给我们带来了扩展运算符,我们就不必再继续使用 apply() 方法了。我们可以将表达式轻松的展开为多个参数。
var myArray = [5, 10, 50];
Math.max(...myArray); // 50
在这里我们通过扩展运算符将 myArray 展开成了一个个单独的值。虽然 ES5 中我们可以通过 apply() 方法来模拟扩展运算符,但是语法上让人迷惑,并且缺少可扩展性。扩展运算符不仅易于使用,还带来了许多新的特性。比如,你可以在函数调用时多次使用扩展运算符,并且还可以和其他参数混合在一起。
function myFunction() {
for(var i in arguments){
console.log(arguments[i]);
}
}
var params = [10, 15];
myFunction(5, ...params, 20, ...[25]); // 5 10 15 20 25
3.REST 参数
rest 参数和扩展运算符是一样的语法,但是他不是将数组展开成一个个的参数,而是将一个个参数转换为数组。
function myFunction(...options) {
console.log(options);
}
myFunction('a', 'b', 'c'); // ["a", "b", "c"]
如果没有提供参数,rest 参数会被设置为空数组:
function myFunction(...options) {
console.log(options);
}
myFunction(); // []
创建参数数量可变的函数:
ES5的写法,利用arguments这个数组
//下面这个方法的作用是传入多个参数,判断第二个开始的参数跟第一个是否相同
function checkSubstrings(string) {
for (var i = 1; i < arguments.length; i++) {
if (string.indexOf(arguments[i]) === -1) {
return false;
}
}
return true;
}
checkSubstrings('this is a string', 'is', 'this'); // true
ES6的写法,利用rest
function checkSubstrings(string, ...keys) {
for (var key of keys) {
if (string.indexOf(key) === -1) {
return false;
}
}
return true;
}
checkSubstrings('this is a string', 'is', 'this'); // true
REST只能是最后一个参数,否则会导致语法错误。
4.默认参数
ES5 中 JavaScript 并不支持默认值,但这里有个很简单的实现,使用 OR
运算符(||),我们可以很容易的模拟默认参数,看下面的代码:
function foo(param1, param2) {
param1 = param1 || 10;
param2 = param2 || 10;
console.log(param1, param2);
}
foo(5, 5); // 5 5
foo(5); // 5 10
foo(); // 10 10
这种方法在函数内很常用,但也存在瑕疵。如果传递 0
或者 null
也会返回默认值。因为它们被认为是 falsy 值。所以如果我们确实需要给函数传递 0
或者 null
,我们需要换种方法来检测参数是否缺失:
function foo(param1, param2) {
if(param1 === undefined){
param1 = 10;
}
if(param2 === undefined){
param2 = 10;
}
console.log(param1, param2);
}
foo(0, null); // 0, null
foo(); // 10, 10
虽然解决了传0和null的不足,但是代码量多了且不优雅
看下面ES6的写法
function foo(a = 10, b = 10) {
console.log(a, b);
}
foo(5); // 5 10
foo(0, null); // 0 null
正如你所看到的,忽略参数返回了默认值,但传递 0 或者 null 并没有。我们甚至可以使用函数来产生参数的默认值:
function getParam() {
alert("getParam was called");
return 3;
}
function multiply(param1, param2 = getParam()) {
return param1 * param2;
}
multiply(2, 5); // 10
multiply(2); // 6 (also displays an alert dialog)
需要注意的是,只有缺少第二个参数的时候,gegParam 方法才会执行,所以当我们使用两个参数 multiply() 的时候并不会弹出 alert。
默认参数另一个有意思的特性是在方法声明是可以引用其他参数和变量作为默认参数:
function myFunction(a=10, b=a) {
console.log('a = ' + a + '; b = ' + b);
}
myFunction(); // a=10; b=10
myFunction(22); // a=22; b=22
myFunction(2, 4); // a=2; b=4
甚至可以在函数声明的时候执行操作符:
function myFunction(a, b = ++a, c = a*b) {
console.log(c);
}
myFunction(5); // 36
注意:不像其他语言,JavaScript 是在调用时才计算默认参数的:
function add(value, array = []) {
array.push(value);
return array;
}
add(5); // [5]
add(6); // [6], not [5, 6]
5.解构赋值
function fun({name}) {
console.log(name)
}
let boy={
name:'小明',
age:18
}
fun(boy);
6.类型检查和缺失或多余参数
在强类型的语言中,我们必须在函数声明时声明参数的类型,但 JavaScript 中没有这种特性,在 JavaScript 中,并不关心传递给函数的参数的类型和个数。
假设我们有一个函数,仅接受一个参数。当我们调用这个函数的使用,我们并不限制到底传递给函数多少个参数,甚至可以选择不传,都不会产生错误。
参数的个数可以分为两种情况:
- 参数缺失,缺失的变量赋值为 undefined
- 参数过多
强制参数
函数调用中如果函数缺失,它会被设置为 undefined。我们可以利用这一点,如果参数缺失就抛出错误:
function foo(mandatory, optional) {
if (mandatory === undefined) {
throw new Error('Missing parameter: mandatory');
}
}
在 ES6 中,我们可以更近一步,使用默认参数来设置强制参数:
function throwError() {
throw new Error('Missing parameter');
}
function foo(param1 = throwError(), param2 = throwError()) {
// do something
}
foo(10, 20); // ok
foo(10); // Error: missing parameter
参数个数
ES6:用REST的length
ES5:用arguments的length(arguments在每个函数内都存在,是一个类数组)
网友评论