函数的实参和形参


JavaScript 中的函数定义并未指定函数形参的类型,函数调用也不对传入的实参做类型检查,实际上,JavaScript 甚至不检查传入形参的个数。

可选形参

当调用函数时传入的实参比函数声明时指定的形参个数少时,剩下的形参都将设置为 undefined,为了更好地做到兼容性,应当给省略的参数赋一个合理的默认值:

function getPropertyNames(o, a = []) {
    a = a || [];
    for (var prop in o) a.push(prop);
    return a;
}  

注:可选形参要放到形参列表最后。

可变长的实参列表:实参对象

当调用函数时传入的实参个数超过函数定义时的形参个数时,可以通过参数对象来解决,在函数体内,标识符 arguments 是指向实参对象的引用,实参对象是一个类数组对象,这样通过数字下标就可以访问传入函数的实参值,而不是非要通过形参名来获取,比如我们来看一个返回传入数字最大值的示例:

通过上面两个特性,可以得出这样的结论:JavaScript 默认行为支持实参个数与形参个数不一致,如果小于的话,多出来的形参值都是 undefined,如果大于的话会忽略多出来的实参,如果要获取的话可以通过 arguments 数组访问。

注:arguments 是实参对象而不是真正的数组,此外用到 arguments 访问实参的函数传入的实参个数不能为零。

除了数组元素,实参对象还定义了 calleecaller 属性(在 ECMAScript 5 严格模式下不支持这两个属性的读写操作),callee 属性用于指代当前正在执行的函数,caller 属性用于指代调用当前正在执行函数的函数,因此,通过 caller 属性可以访问调用栈。callee 属性也有其用武之地,比如在匿名函数中递归调用自身:

var factorial = function(x) {
    if (x <= 1) return 1;
    return x * arguments.callee(x-1);
}

将对象属性用作实参

为了避免函数形参太多,给调用和可读性带来困难,可以将参数以对象属性的方式传入和调用:

function easy_copy(args) {
    var from = args.from;
    var to = args.to;
}

实参类型

JavaScript 方法的形参并未声明类型,实参传入函数之前也未做任何类型检查。和 PHP 一样,我们只能在代码真正执行之前对参数作必要的检查,以避免运行时出错:

function sum(a) {
  if (Array.isArray(a)) {
    var total = 0;
    for (var i = 0; i < a.length; i++) {
      var element = a[i];
      if (element == null) 
        continue;
      if (isFinite(element)) 
        total += element;  // 有限数字
      else 
        throw new Error('sum(): elements must be finite element');
    }
  }

  throw new Error('sum(): argument must be array');
}

点赞 取消点赞 收藏 取消收藏

<< 上一篇: 函数调用

>> 下一篇: 用作值的函数