本文深入解析JavaScript函数中默认参数的使用。对比ES5通过逻辑或运算符模拟默认值的局限性与ES6直接在参数定义中赋值的优化。详细探讨默认参数位置对函数length属性的影响、每次调用重新创建默认数组的行为、默认参数与形参的结合方式,以及由let声明引发的单独作用域和暂时性死区现象。
默认参数机制允许在函数定义时为形参指定初始值。当调用函数时未传递该参数,或传入的值明确为
undefined时,系统将自动使用预设的默认值进行初始化。
本文将深入探讨JavaScript中函数默认参数的几个关键细节,涵盖默认值的位置规范、默认参数对函数length属性的具体影响、默认参数在重复调用时的重新创建机制、默认参数与其余形参的结合用法、默认参数产生的独立作用域,以及由此引发的暂时性死区问题。
ES5中的默认参数
在ES5标准中,无法直接在参数列表中指定默认值。开发者通常需要在函数体内声明变量并通过赋值操作来模拟默认值效果,但这种写法不够直观,难以直接体现参数的默认状态。
function fn(x, y) {
var y = y || 1;
return x + y;
}
console.log(fn(2)); // 3如上述代码所示,我们通过||运算符使y成为函数的默认参数,这是ES5时代的典型实现方式。然而,当参数期望接收布尔值时,这种写法极易导致逻辑判断错误,因为0、null或false等假值也会被判定为无效而使用默认值。
接下来,我们将介绍ES6标准为解决上述问题而引入的全新特性——默认参数的原生支持。
全新默认参数的诞生
ES6允许在函数参数定义阶段直接进行默认赋值。这一特性不仅优化了代码结构,还显著提升了代码的可读性和维护体验。
function fn(x, y=1) {
return x + y;
}
console.log(fn(2)); // 3需要注意的是,在参数定义时赋予默认值涉及若干细节规范,开发者需格外留意。
默认位置
默认参数值必须位于参数列表的尾部,即尾参数位置。以下代码演示了若将默认参数置于非尾部位置所引发的异常行为。
function fn(x = 1, y) {
return [x, y];
}
console.log(fn(2)); // [ 2, undefined ]此种情况下,我们无法通过仅控制x无值来触发x使用默认值。不过,可以通过显式传入undefined来强制使用默认参数,从而规避此限制。
function fn(x = 1, y) {
return [x, y];
}
console.log(fn(undefined,2)); // [ 1, 2 ]即便如此,仍强烈建议将默认参数定义在参数列表的尾部,其中一个重要原因是其会干扰函数length属性的计算结果。
默认参数对函数的length属性的影响
函数的length属性用于返回函数的形参数量,但该计数不包含默认参数。这里存在一个关键细节:它仅返回位于默认参数之前的形式参数数量。
console.log(function fn(x, y = 1, z) {}.length); // 1在上述函数中,x被赋予了默认值,因此其length属性仅返回x之前的形式参数数量。基于此行为,建议始终将默认参数置于参数定义的尾部。
重新创建的默认参数
函数每次被调用时,其参数会被重新创建。默认参数存在一个特殊行为:它是否会因函数的重复调用而被重新创建?在JS环境中,答案是肯定的。请看以下示例。
function fn(x, num = []) {
num.push(x);
return num;
}
console.log(fn(1)); // [1]
console.log(fn(2)); // [2]通过上述代码两次调用fn函数并向num添加元素,每次调用返回的结果均证明:每次调用函数时,都会重新创建默认的num对象。
默认参数与形参的结合使用
我们可以将默认参数与前面的形参结合使用,具体实现如下。
function fn(x, y, z = [x, y, 1]) {
return z;
}
console.log(fn(1, 2)); // [ 1, 2, 1 ]通过尾部的默认参数与前面的形式参数相结合,默认值可以是字符串、数组,也可以是表达式,例如:fn(x, y, z = x + y)。
默认参数的作用域问题
深入探究默认参数的原理,其本质是利用let来声明默认参数。这导致了一个现象:使用默认参数时,会开辟一个单独的作用域。在该作用域内访问变量时,会执行特定的查找步骤。为了更好地理解参数作用域,我们参考以下代码说明这一过程。
let x = 1
function() fn(y = x) {
return y
}
console.log(fn()) // 1由于y = x是默认参数,因此参数定义区域形成了一个独立的作用域。在赋值过程中,引擎与该作用域进行如下交互(此处忽略LHS与RHS查询,非本文重点)。
- 引擎在为
y赋值时,会询问当前作用域是否已见过x。当前作用域即参数声明的作用域,回答为“没有”。 - 引擎随后向上查找,询问上级作用域(此时为全局作用域),回答为存在
x,引擎最终为y赋值。
通过这个简单示例可以理解默认参数的作用域机制,这种现象非常常见,例如在for循环中。
for(let i = 0; i < 100; i++) {}默认参数的隐藏性死区(隐藏的暂时性死区)
在之前关于let与const命令的文章中提到了暂时性死区(TDZ)的概念。由于默认参数的特性,同样会引发暂时性死区现象。
暂时性死区:在代码块中使用let声明变量之前,该变量不可用,这种现象称为暂时性死区。
var x = 1
function fn(x = x) {
return x;
}在参数内x = x其本质为let x = x在= x的时候会出现暂时性死区的现象。因为在此刻出现问题的是=后的x,此时对x进行访问。而此刻在该作用域内let x之前,没有声明x,所以该变量不可用,即我们所说的暂时性死区的现象。
参考文献
- ES6标准入门
- 你不知道的javascript上卷
- MDN
到此这篇关于深入JS函数中默认参数的使用详解的文章就介绍到这了,更多相关JS函数默认参数内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!