默认参数值
-
在 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}`; }