0
function func(x = y, y = 2) { 
    return [x, y];
}

func(); // ReferenceError: y is not defined
func(1); // [1, 2]

As the code above implied, there is a hidden TDZ in the function parameters scope, which explains why the code below fails:

function func(arg) {
    let arg = 1; // SyntaxError: Identifier 'arg' has already been declared
}

So function parameters should be declared with let, but what confused me is :

function func(arg) {
    var arg = 1;
    console.log(arg); // 1
}

this code works fine.

Why you can redeclare variables using var? How does Javascript declare function parameters?


edit: I know exactly you can't use let to redeclare a variable. The question here is if function parameters is declared using let, so:

function func(arg) {
    var arg = 1;
}

is like:

let arg; // arg parameter declares here
var arg = 1; // func body 

and why this can run without an exception?

jerrypy
  • 139
  • 1
  • 2
  • 14
  • 2
    `var` is legacy syntax, but `let` is new. It's just a quirk. – Pointy Oct 11 '17 at 14:46
  • 1
    https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable – Abhi Oct 11 '17 at 14:47
  • 1
    You should not redeclare function parameters, they are already declared when entering the function body. – Teemu Oct 11 '17 at 14:48
  • @Pointy I think you are the only one understand the question here and maybe this was because V8 has to compatible with ES5. But still have to confirm with someone really into V8. – jerrypy Oct 11 '17 at 15:32

7 Answers7

3

there is a hidden TDZ in the function parameters scope

Yes indeed. Have a look here for some more examples.

How does Javascript declare function parameters?

As parameters - see here for a step-by-step explanation. They're neither the same as let nor the same as var, they have their own semantics. ES6, which introduced default initialisers, gave them the same TDZ limitations as in let to catch more programmer mistakes.

Why you can redeclare variables using var?

Because until ES5, redeclaring a variable was not an error condition, and this behaviour needed to be preserved to not break the web. It could only be introduced for new features, like let and const - or argument lists that use default initialisers, try function x(bar, bar) {} vs function x(bar, bar=1){}.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

This isn't necessarily related to the function's arguments.

This will throw an error as well:

function func() {
    var arg = 1;
    let arg = 2
    console.log(arg); // 1
}

func();

You just can't use let to re-declare a variable, while var isn't that strict: var doesn't try to re-declare the variable if it's already declared. It just assigns the new value.

For more information on the specifics of let, see this MDN page on the let statement.

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
  • Yeah, I'm confused on why this got downvoted too... (You could add a [link to the documentation stating this though](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let)) – George Oct 11 '17 at 14:53
  • In my question, I think parameters are declared using `let`, so the question is like why `let arg ; var arg = 1;` should throw an exception but not? – jerrypy Oct 11 '17 at 14:57
  • @George: Thanks. I added a link. – Cerbrus Oct 11 '17 at 14:58
  • @jerrypy: It doesn't matter if the parameters are declared using `let` or `var`, internally. For re-declaration, all that matters is that the variable is already declared. – Cerbrus Oct 11 '17 at 14:59
1

The reason that is, is because of something that people in the JavaScript community refer to as "hoisting" when you do var arg = 1 that gets translated into var arg; arg = 1; however if var has already been defined as is the case here because of the function parameter, then the compiler tries to be helpful and ignores subsequent re-declarations instead of throwing an error... which is probably an unexpected behaviour, and hasn't been followed through with the new let variable declaration, however, it has to stay there for backwards compatibility reasons.

linasmnew
  • 3,907
  • 2
  • 20
  • 33
0

let is added more recently and with it, an error throw was introduced that manifests when you try to declare a variable that involves let twice. This does not happen with var which will simply replace the old value, unless the variable has been already declared with let.

function func(arg) {
    let arg = 1; // not ok, because `let` knows that `arg` is being redeclared
}

function func(arg) {
    var arg = 1; // ok, because `var` will just replace the value of `arg`
}

function func() {
    let arg = 0;
    var arg = 1; // not ok, because `let` declared `arg` already
}

Here is a link to the MDN for let which explains the feature.

M0nst3R
  • 5,186
  • 1
  • 23
  • 36
  • 1
    if you declare a variable using `let` first ,then redeclare it with `var`, it can't replace the value. `let arg; var arg = 1;` this will throw an exception. – jerrypy Oct 11 '17 at 15:07
  • Interesting, did not know that, I updated the answer. – M0nst3R Oct 11 '17 at 15:10
0

So var is legacy syntax and ideally you probably want to avoid using it.

Instead using let for variables that can be reassigned, and const for constants.

var also has global scope where as let and const are limited to the scope they are in.

Josh
  • 1,517
  • 1
  • 13
  • 21
0

Parameter bindings does not exactly follow the same behavior as the ones declared with let.

1) Parameter bindings get created before var bindings. var doesn't create bindings that already exist, so there's never a problem there. let however creates bindings after var.

2) There's an early error on all productions that create a scope that has it as a rule that no lexical binding can occur when there's already a variable declaration with the same name.

MinusFour
  • 13,913
  • 3
  • 30
  • 39
-2

The first example will not throw an error a value if an argument is passed to func call.

var does not have the same scope as let or const.

guest271314
  • 1
  • 15
  • 104
  • 177
  • This doesn't answer why the `let` re-declaration throws an error, while using `var` to do the same doesn't. – Cerbrus Oct 11 '17 at 14:49
  • @Cerbrus Because `arg` is already defined, `arg = 1` will not throw an error. A variable declared using `let` or `var` can be set to a new value. A `const` declaration cannot be re-defined or deleted. – guest271314 Oct 11 '17 at 14:51
  • This question isn't about assignment. It's about declaring it a second time. – Cerbrus Oct 11 '17 at 14:52
  • @Cerbrus _"This question isn't about assignment. It's about declaring it a second time."_ ? Unless you are OP or clairvoyant you cannot conclusively state what the question is "about". The Question covers several topics – guest271314 Oct 11 '17 at 14:53
  • @jerrypy See also [Is it possible to delete a variable declared using const?](https://stackoverflow.com/questions/42424019/is-it-possible-to-delete-a-variable-declared-using-const), [Why does .then() chained to Promise.resolve() allow const declaration to be reassigned?](https://stackoverflow.com/questions/45380637/why-does-then-chained-to-promise-resolve-allow-const-declaration-to-be-reas) – guest271314 Oct 11 '17 at 15:01