3

I'm a bit confused about how scope & variable assignment within a function seems to change when assigning a default parameter value for that function.

For example, when this function has a default value assigned to parameter i, the output array variable appears to be block-scoped when inspected with Chrome Dev Console,:

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

steps(10, 20);

a

However, by removing the default parameter value for i, the output array variable is scoped locally:

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

steps(10, 20);

enter image description here

Why does assigning a default value to parameter i affect the scope of the output array variable?

I was initially made aware of this shift in function scope by attempting to run the following segment of code through pythontutor.com's live programming environment for Javascript. Even though the code executes as expected within an IDE, it fails to run due to scope issues on 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);  

The pythontutor processor halts execution three steps in, at the invocation of print() just after declaring the output variable. Pythontutor.com will, however, execute the code as expected if I declare the output variable globally first:

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);
2
  • 1
    are you using babel by any chance? If it's being rewritten, it's likely changing how the parameters are accessed. Commented Jan 18, 2018 at 22:32
  • Scratch that, just ran the test code in the chrome dev tools directly and sure enough the scope does change depending on whether or not there's a default parameter defined for the function. Commented Jan 18, 2018 at 22:42

1 Answer 1

1

It's because default initialisers run in their own scope. Only if there are none, the body code is evaluated in the top function scope. It would only make a difference if you put a function expression in a default initaliser, which may close over the other parameters but does not have access to the variables that will be declared in the body.

Basically it's the difference between

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

and

function steps() {
  var n = arguments[0],
      i = arguments.length > 0 ? arguments[1] : 40;
  (() => {
    var output = [n];
  }());
}
Sign up to request clarification or add additional context in comments.

1 Comment

OK! That seems to explain it. I have some reading to do regarding ECMAScript 2015 FunctionDeclarationInstantiation and Environment Records.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.