最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - declaring a variable twice in IIFE - Stack Overflow

programmeradmin0浏览0评论

I came through this fun quiz on the internet.

console.log((function(x, f = (() => x)){
  var x;
  var y = x;
  x = 2;
  return [x, y, f()]
})(1))

and the choices were:

  1. [2,1,1]

  2. [2, undefined, 1]

  3. [2, 1, 2]

  4. [2, undefined, 2]

I picked solution 2 TBH, basing that on that x has been redefined, y was declared and defined with no value, and that f has a different scope hence getting the global x memory spot than function x memory spot.

However, I tried it in jsbin

and I found it was solution 1, while I was not sure why that happened I messed with the function body and I removed var x from the function body, I found that the response changed to #3 which makes sense as x value changed and hence it showed x and f as 2 and y as 1 which was declared globally.

but still I can't get why it shows 1 instead of undefined.

I came through this fun quiz on the internet.

console.log((function(x, f = (() => x)){
  var x;
  var y = x;
  x = 2;
  return [x, y, f()]
})(1))

and the choices were:

  1. [2,1,1]

  2. [2, undefined, 1]

  3. [2, 1, 2]

  4. [2, undefined, 2]

I picked solution 2 TBH, basing that on that x has been redefined, y was declared and defined with no value, and that f has a different scope hence getting the global x memory spot than function x memory spot.

However, I tried it in jsbin.com

and I found it was solution 1, while I was not sure why that happened I messed with the function body and I removed var x from the function body, I found that the response changed to #3 which makes sense as x value changed and hence it showed x and f as 2 and y as 1 which was declared globally.

but still I can't get why it shows 1 instead of undefined.

Share Improve this question asked Apr 7, 2019 at 14:28 HM107HM107 1,4011 gold badge14 silver badges29 bronze badges 8
  • 1 I find the best way to figure these things out is to step through them line by line with a debugger, and/or print out the values after each line. – Heretic Monkey Commented Apr 7, 2019 at 14:31
  • var x; doesn't define a new variable within the function scope, where var x = somevalue; would – Alex Commented Apr 7, 2019 at 14:39
  • 2 @alex it does. ... – Jonas Wilms Commented Apr 7, 2019 at 14:41
  • @JonasWilms I see, would have expected x to be undefined then, implicitly copy the function formal value looks really odd to me. – Alex Commented Apr 7, 2019 at 14:51
  • 4 I'm glad this question was asked :) – Pointy Commented Apr 7, 2019 at 15:06
 |  Show 3 more comments

2 Answers 2

Reset to default 24

but still I can't get why it shows 1 instead of undefined.

It's not just you. This is a deep, dark part of the specification. :-)

The key here is that there are two xs. Yes, really. There's the parameter x, and there's the variable x.

A parameter list containing expressions (like f's default value) has its own scope separate from the function body's scope. But prior to parameter lists possibly having expressions, having var x within a function with an x parameter had no effect (x was still the parameter, with the parameter's value). So to preserve that, when there's a parameter list with expressions in it, a separate variable is created and the value of the parameter is copied to the variable at the beginning of the function body. Which is the reason for this seemingly-odd (no, not just seemingly) odd behavior. (If you're the kind who likes to dive into the spec, this copying is Step 28 of FunctionDeclarationInstantiation.)

Since f's default value, () => x, is created within the parameter list scope, it refers to the parameter x, not the var.

So the first solution, [2, 1, 1] is correct, because:

  • 2 was assigned to the var x in the function body. So at the end of the function, the var x is 2.
  • 1 was assigned to y from the var x before x got the value 2, so at the end of the function, y is 1.
  • The parameter x's value has never changed, so f() results in 1 at the end of the function

It's as though the code were written like this instead (I've removed unnecessary parens and added missing semicolons):

console.log(function(param_x, f = () => param_x) {
  var var_x = param_x;
  var y = var_x;
  var_x = 2;
  return [var_x, y, f()];
}(1));

...I removed var x from the function body, I found that the response changed to #3...

#3 is [2, 1, 2]. That's correct, because when you remove the var x from the function, there's only one x, the parameter (inherited by the function body from the parmeter list). So assigning 2 to x changes the parameter's value, which f returns.

Taking the earier example with param_x and var_x, here's what it looks like if you remove the var x; from it:

console.log(function(param_x, f = () => param_x) {
  var y = param_x;
  param_x = 2;
  return [param_x, y, f()];
}(1));


Here's an annotated description of the original code (with the extraneous parentheses removed and missing semicolons added):

//                   /---- the parameter "x"
//                   v  vvvvvvvvvvv--- the parameter "f" with a default value
console.log(function(x, f = () => x) {
  var x;      // <=== the *variable* x, which gets its initial value from the
              //      parameter x
  var y = x;  // <=== sets y to 1 (x's current value)
  x = 2;      // <=== changes the *variable* x's value to 2
  //      +---------- 2, because this is the *variable* x
  //      |  +------- 1, because this is the variable y
  //      |  |   +--- 1, because f is () => x, but that x is the *parameter* x,
  //      |  |   |       whose value is still 1
  //      v  v  vvv
  return [x, y, f()];
}(1));

Final note regarding your title:

declaring a variable twice in IIFE

The variable is only declared once. The other thing is a parameter, not a variable. The distinction is rarely important...this being one of those rare times. :-)

The tricky part of that code is that the => function is created as part of a default parameter value expression. In parameter default value expressions, the scope includes the parameters declared to the left, which in this case includes the parameter x. Thus for that reason the x in the => function is in fact the first parameter.

The function is called with just one parameter, 1, so when the => function is called that's what it returns, giving [2, 1, 1].

The var x declaration, as Mr Crowder points out, has the (somewhat weird, at least to me) effect of making a new x in the function scope, into which is copied the value of the parameter x. Without it, there's only the one (the parameter).

发布评论

评论列表(0)

  1. 暂无评论