--- title: let slug: Web/JavaScript/Reference/Statements/let page-type: javascript-statement browser-compat: javascript.statements.let sidebar: jssidebar --- The **`let`** declaration declares re-assignable, block-scoped local variables, optionally initializing each to a value. {{InteractiveExample("JavaScript Demo: let declaration")}} ```js interactive-example let x = 1; if (x === 1) { let x = 2; console.log(x); // Expected output: 2 } console.log(x); // Expected output: 1 ``` ## Syntax ```js-nolint let name1; let name1 = value1; let name1 = value1, name2 = value2; let name1, name2 = value2; let name1 = value1, name2, /* …, */ nameN = valueN; ``` ### Parameters - `nameN` - : The name of the variable to declare. Each must be a legal JavaScript [identifier](/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers) or a [destructuring binding pattern](/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring). - `valueN` {{optional_inline}} - : Initial value of the variable. It can be any legal expression. Default value is `undefined`. ## Description The scope of a variable declared with `let` is one of the following curly-brace-enclosed syntaxes that most closely contains the `let` declaration: - [Block](/en-US/docs/Web/JavaScript/Reference/Statements/block) statement - {{jsxref("Statements/switch", "switch")}} statement - {{jsxref("Statements/try...catch", "try...catch")}} statement - Body of [one of the `for` statements](/en-US/docs/Web/JavaScript/Reference/Statements#iterations), if the `let` is in the header of the statement - Function body - [Static initialization block](/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks) Or if none of the above applies: - The current [module](/en-US/docs/Web/JavaScript/Guide/Modules), for code running in module mode - The global scope, for code running in script mode. Compared with {{jsxref("Statements/var", "var")}}, `let` declarations have the following differences: - `let` declarations are scoped to blocks as well as functions. - `let` declarations can only be accessed after the place of declaration is reached (see [temporal dead zone](#temporal_dead_zone_tdz)). For this reason, `let` declarations are commonly regarded as [non-hoisted](/en-US/docs/Glossary/Hoisting). - `let` declarations do not create properties on {{jsxref("globalThis")}} when declared at the top level of a script. - `let` declarations cannot be [redeclared](#redeclarations) by any other declaration in the same scope. - `let` begins [_declarations_, not _statements_](/en-US/docs/Web/JavaScript/Reference/Statements#difference_between_statements_and_declarations). That means you cannot use a lone `let` declaration as the body of a block (which makes sense, since there's no way to access the variable). ```js-nolint example-bad if (true) let a = 1; // SyntaxError: Lexical declaration cannot appear in a single-statement context ``` Note that `let` is allowed as an identifier name when declared with `var` or `function` in [non-strict mode](/en-US/docs/Web/JavaScript/Reference/Strict_mode), but you should avoid using `let` as an identifier name to prevent unexpected syntax ambiguities. Many style guides (including [MDN's](/en-US/docs/MDN/Writing_guidelines/Code_style_guide/JavaScript#variable_declarations)) recommend using {{jsxref("Statements/const", "const")}} over `let` whenever a variable is not reassigned in its scope. This makes the intent clear that a variable's type (or value, in the case of a primitive) can never change. Others may prefer `let` for non-primitives that are mutated. The list that follows the `let` keyword is called a _{{Glossary("binding")}} list_ and is separated by commas, where the commas are _not_ [comma operators](/en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator) and the `=` signs are _not_ [assignment operators](/en-US/docs/Web/JavaScript/Reference/Operators/Assignment). Initializers of later variables can refer to earlier variables in the list. ### Temporal dead zone (TDZ) A variable declared with `let`, `const`, or `class` is said to be in a "temporal dead zone" (TDZ) from the start of the block until code execution reaches the place where the variable is declared and initialized. While inside the TDZ, the variable has not been initialized with a value, and any attempt to access it will result in a {{jsxref("ReferenceError")}}. The variable is initialized with a value when execution reaches the place in the code where it was declared. If no initial value was specified with the variable declaration, it will be initialized with a value of `undefined`. This differs from {{jsxref("Statements/var", "var", "hoisting")}} variables, which will return a value of `undefined` if they are accessed before they are declared. The code below demonstrates the different result when `let` and `var` are accessed in code before the place where they are declared. ```js example-bad { // TDZ starts at beginning of scope console.log(bar); // "undefined" console.log(foo); // ReferenceError: Cannot access 'foo' before initialization var bar = 1; let foo = 2; // End of TDZ (for foo) } ``` The term "temporal" is used because the zone depends on the order of execution (time) rather than the order in which the code is written (position). For example, the code below works because, even though the function that uses the `let` variable appears before the variable is declared, the function is _called_ outside the TDZ. ```js { // TDZ starts at beginning of scope const func = () => console.log(letVar); // OK // Within the TDZ letVar access throws `ReferenceError` let letVar = 3; // End of TDZ (for letVar) func(); // Called outside TDZ! } ``` Using the `typeof` operator for a variable in its TDZ will throw a {{jsxref("ReferenceError")}}: ```js example-bad { typeof i; // ReferenceError: Cannot access 'i' before initialization let i = 10; } ``` This differs from using `typeof` for undeclared variables, and variables that hold a value of `undefined`: ```js console.log(typeof undeclaredVariable); // "undefined" ``` > [!NOTE] > `let` and `const` declarations are only processed when the current script gets processed. If you have two `