(edit) I found out there's another post: "Where are arguments positioned in the lexical environment?" that is directly related to my question.
When I was reading "You Don't Konw JS", I did some experiments to shadow parameters by declaring local variables in the function, and then I met some weird situations that I am not able to explain, so I posted my code here to seek some help.
Please take a look at the "case 2" of the following code, and see if you can tell what's happening, thanks.
My questions: (in "case 2")
- Are "parameter list" and "function body" in the same scope ?
- if so,
var id = 5
should be considered a "redeclaration", parameterid
would be updated by the redeclaration, but it's NOT, why ? (see: (***) below) - if they're not in the same scope, why can't we shadow
the (outer) parameter
id
with a local "let", like we do in a "for-loop" ? (see: (*) below)
- if so,
const { log } = console;
let count = 0;
// (*)
// ⭐ "initialization block" in a for-loop
// ---------------------------------------
// ╭──init───╮
for ( let i = 0 ; i < 3 ; i++ ) {
// ⭐ for-loop body (block scope) and the "initialization block"
// are in different scopes, so we can "shadow" the outer `i`
// with a local "let" without any problem.
let i = 1;
log(i); // 1, 1, 1
if (++count > 3) break; // prevent infinite loop
}
// ⭐ case 1: (alters parameter directly)
// ---------------------------------------
// • parameter `id` is closed over by `defaultID`.
//
// ╭─── parameter list ───╮
function doUpdate(id, defaultID = () => id) {
id = 5; // ✅ parameter `id` updated (see (**) below)
log( defaultID() );
}
// (**)
doUpdate(3); // ✅ 5
// ⭐ case 2: (shadows parameter by local "var")
// ----------------------------------------------
//
// ╭─── parameter list ───╮
function doesntUpdate(id, defaultID = () => id) {
// ----------------------
// ❓ weird situation ❓
// ----------------------
// ❗ 2.1: can't shadow parameters by "let" variables
// ----------------------------------------------------------
// let id = 5;
// ^^
// ⛔ SyntaxError: Identifier 'id' has already been declared
// ----------------------------------------------------------
log( defaultID() ); // 3
// ⭐ 2.2 use "var" instead:
// -------------------------
var id = 5; // ❗ this do shadow parameter `id`
log(id); // 5
log( defaultID() ); // 3
// ----------------------------------------------------------------
// ⭐ are "parameter list" and "function body" in the same scope ❓
// ----------------------------------------------------------------
//
// • if so, `var id = 5` should be considered a "redeclaration",
// parameter `id` would be updated by the redeclaration,
// but it's NOT, why ❓ (see: (***) below)
// (Q: is parameter `i` a "var" ?)
//
// • if they're not in the same scope, why can't we shadow
// the (outer) parameter `id` with a local "let", like we
// do in a "for-loop"❓ (see: (*) above)
//
// ----------------------------------------------------------------
}
// (***)
doesntUpdate(3); // ❗ (parameter `id` is not updated)