JS:默认函数参数值和作用域

3

在函数中,当为参数i分配默认值时,作用域和变量赋值似乎会发生变化,这让我有点困惑。

例如,当此函数的参数具有默认值时,output数组变量在使用Chrome开发者工具进行检查时似乎被块级作用域限制:

function steps(n, i = 40) {
 var output = [n];
}

steps(10, 20);

a

然而,通过移除 i 的默认参数值,输出 数组变量的作用域仅限于本地:

function steps(n, i) {
  var output = [n];
}

steps(10, 20);

图片描述在此输入

为什么给参数 i 赋默认值会影响 output 数组变量的作用域?

我最初是通过尝试在 pythontutor.com 的 JavaScript 实时编程环境中运行以下代码段来了解函数作用域的变化。即使代码在 IDE 中按预期执行,但由于作用域问题,在 pythontutor 上无法运行:

function steps(n, i = 1) {
  // declare base case
  if (n === 0) 
    return;

  var output = [];
  print(i, "#");
  print(n - 1, " ");
  console.log(output.join(""));

  // make recursive call
  steps(n - 1, i + 1);

  function print(num, char) {
    for (let j = 0; j < num; j++) {
      output.push(`${char}`);
    }
  }
}


steps(3);  

PythonTutor 处理器在声明 output 变量后第三步就会执行 print() 并停止运行。不过,如果我先在全局范围内声明 output 变量,Pythontutor.com 就会按照预期执行代码:

var output = [];

function steps(n, i = 1) {
  // declare base case
  if (n === 0) 
    return;

  output = [];
  print(i, "#");
  print(n - 1, " ");
  console.log(output.join(""));

  // make recursive call
  steps(n - 1, i + 1);

  function print(num, char) {
    for (let j = 0; j < num; j++) {
      output.push(`${char}`);
    }
  }
}


steps(3);

1
你有没有碰巧在使用 Babel?如果它正在被重写,很可能会改变参数的访问方式。 - zzzzBov
算了,我刚刚直接在Chrome开发工具中运行了测试代码,果然作用域会根据函数是否定义了默认参数而改变。 - zzzzBov
1个回答

1
因为默认初始化程序在它们自己的作用域中运行。只有在没有这些初始化程序时,主体代码才会在顶层函数作用域中评估。只有在将函数表达式放入默认初始化程序中时才会有所区别,这可能会关闭其他参数,但无法访问将在主体中声明的变量。
基本上就是区别在于:
function steps() {
  var n = arguments[0],
      i = arguments[1];
  var output = [n];
}

并且

function steps() {
  var n = arguments[0],
      i = arguments.length > 0 ? arguments[1] : 40;
  (() => {
    var output = [n];
  }());
}

好的!这似乎解释清楚了。我需要阅读有关ECMAScript 2015 FunctionDeclarationInstantiation和Environment Records的内容。 - Brian Patrick Hummel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接