默认参数值

158 阅读2分钟

默认参数值

  • 在 ECMAScript5.1 及以前,实现默认参数的一种常用方式就是检测某个参数是否等于 undefined,如果是则意味着没有传这个参数,那就给它赋一个值:

    function makeKing(name) {
      name = typeof name === undefined ? name : "Henry";
      return `King ${name} VIII`;
    },
    console.log(makeKing()); // King Henry VIII
    console.log(makeKing('ZhangSan')) // King ZhangSan VIII
    
  • ECMAScript6 之后就不用这么麻烦了因为它支持显示定义默认参数了。下面就是与前面代码等价的 ES6 写法,只要在函数定义中的参数后面用 "=" 就可以为参数赋一个默认值:

    function makeKing(name = "Henry") {
      return `King ${name} VIII`;
    }
    console.log(makeKing()); // King Henry VIII
    console.log(makeKing("ZhangSan")); // King ZhangSan VIII
    
  • 给参数传 undefined 相当于没有传值,不过这样可以利用多个独立的默认值:

    function makeKing(name = "Henry", numerals = "VIII") {
      return `King ${name} ${numerals}`;
    }
    console.log(makeKing()); // King Henry VIII
    console.log(makeKing("ZhangSan")); // King ZhangSan VIII
    console.log(makeKing(undefined, "VII")); // King Henry VII
    
  • 在使用默认参数时,arguments 对象的值不反应参数的默认值,只反映传给函数的参数。当然,跟 ES5 严格模式一样,修改命名参数也不会影响 arguments 对象,它始终以调动函数传入的值为准:

    function makeKing(name = "henry") {
      name = "ZhangSan";
      return `King ${arguments[0]}`;
    }
    console.log(makeKing()); // King undefined;
    console.log(makeKing("ZhangSan")); // King ZhangSan
    
  • 默认参数值并不限于原始值或对象类型,也可以使用调用函数返回的值:

    let romanNumerals = ["I", "II", "III", "IV", "V", "VI"];
    let ordinality = 0;
    function getNumerals() {
      // 每次调用后递增
      return romanNumerals[ordinality++];
    }
    
    function makeKing(name = "Henry", numerals = getNumerals) {
      return `King ${name} ${numerals}`;
    }
    console.log(makeKing()); // King Henry I
    console.log(makeKing("ZhangSan", "XVI")); // King ZhangSan XVI
    console.log(makeKing()); //King Henry II
    console.log(makeKing()); //King Henry III
    
  • 函数的默认参数只有在函数被调用时才会求值,不会在函数定义时求值。而且,计算默认值的函数只有在调用函数但未传相应参数时才会被调用。

  • 箭头函数同样也可以这样使用默认参数,只不过在只用一个参数时,就必须使用括号而不能省略了:

    let makeKing = (name = "Henry") => `King ${name}`;
    console.log(makeKing()); // King Henry
    

默认参数作用域与暂时性死区

  • 因为在求值默认参数时可以定义对象,也可以动态调用函数,所以函数参数肯定实在某个作用域中求值的。

    //给多个参数定义默认值实际上跟使用 let 关键字顺序声明变量一样。来看下面的例子:
    function makeKing(name = "Henry", numerals = "VIII") {
      return `King ${name} ${numerals}`;
    }
    console.log(makeKing()); // King Henry VIII
    // 这里的默认参数会按照定义它们的顺序依次被初始化。可以依照如下示例想像一下这个过程:
    function makeKing() {
      let name = "Henry";
      let numerals = "VIII";
      return `King ${name} ${numerals}`;
    }
    // 因为参数是按顺序初始化的,所以后定义默认值的参数可以引用先定义的参数。看下面例子:
    function makeKing(name = "henry", numerals = name) {
      return `King ${name} ${numerals}`;
    }
    console.log(makeKing()); //King Henry Henry
    // 参数初始化顺序遵循“暂时性死区”规则,既前面定义的参数不能引用后面定义的。像这样就会抛出错误:
    //调用时不传第一个参数会报错
    function makeKing(name = numerals, numerals = "VIII") {
      return `King ${name} ${numerals}`;
    }
    //参数也存在于自己的作用域中,它们不能引用函数体的作用域:
    // 调用时不传第二个参数会报错
    function makeKing(name = "Henry", numerals = defaultNumeral) {
      let defaultNumeral = "VIII";
      return `King ${name} ${numerals}`;
    }