乐闻世界logo
搜索文章和话题

Let 和 var 有什么区别

8 个月前提问
3 个月前修改
浏览次数120

20个答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

在JavaScript中,letvar都可用于声明变量,但它们之间存在几个关键的区别:

  1. 作用域
    • var声明的变量拥有函数作用域,如果在函数之外声明,则为全局作用域。
    • let声明的变量拥有块级作用域(block scope),即只在其声明的块或子块中有效。

例子

javascript
function varTest() { if (true) { var x = 2; } console.log(x); // 输出2,因为x在整个函数中都是可见的 } function letTest() { if (true) { let y = 2; } console.log(y); // 引发错误,y不可见,因为它只在if块中有效 }
  1. 变量提升
    • var声明的变量会被提升至函数或全局作用域的顶部,但是在执行到声明语句之前,变量的值是undefined
    • let声明的变量也存在提升,但不会被初始化。在代码执行到声明语句之前,它不可以被访问,这个区间称为“暂时性死区”(temporal dead zone)。

例子

javascript
console.log(a); // 输出undefined,因为var声明的变量被提升了 var a = 3; console.log(b); // 引发ReferenceError错误,因为此时b还在暂时性死区 let b = 4;
  1. 重复声明
    • 使用var声明变量时,可以在同一作用域中重复声明同一个变量而不会出错。
    • 使用let声明变量时,不允许在相同作用域内重复声明同一个变量。

例子

javascript
var c = 1; var c = 2; // 有效,不会出错 let d = 1; let d = 2; // 无效,会引发SyntaxError错误
  1. 全局对象的属性
    • 在全局作用域中,用var声明变量会创建一个新的全局对象的属性。
    • let在全局作用域中声明变量不会在全局对象中添加属性。

例子

javascript
var e = 5; // 在浏览器中,window.e将会是5 let f = 5; // 在浏览器中,window.f将是undefined

总结来说,let提供了比var更严格的作用域控制,是ES6引入的,以解决var引起的一些作用域问题并提供更好的代码管理方式。在现代JavaScript编程中,一般推荐使用let(和const)来代替var

2024年6月29日 12:07 回复

范围规则

主要区别在于范围规则。由关键字声明的变量的作用域var为直接函数体(因此为函数作用域),而let变量的作用域为由 表示的直接_封闭_块{ }(因此为块作用域)。

shell
function run() { var foo = "Foo"; let bar = "Bar"; console.log(foo, bar); // Foo Bar { var moo = "Mooo" let baz = "Bazz"; console.log(moo, baz); // Mooo Bazz } console.log(moo); // Mooo console.log(baz); // ReferenceError } run();

运行代码片段Hide results

展开片段

let语言中引入关键字的原因是函数作用域令人困惑,并且是 JavaScript 中错误的主要来源之一。

看一下另一个 Stack Overflow 问题中的示例:

shell
var funcs = []; // let's create 3 functions for (var i = 0; i < 3; i++) { // and store them in funcs funcs[i] = function() { // each should log its value. console.log("My value: " + i); }; } for (var j = 0; j < 3; j++) { // and now let's run each one to see funcs[j](); }

运行代码片段Hide results

展开片段

My value: 3``funcs[j]();由于匿名函数绑定到同一变量,因此每次调用时都会输出到控制台。

人们必须创建立即调用的函数来从循环中捕获正确的值,但这也很麻烦。

吊装

使用关键字声明的变量var被提升并_初始化_,这意味着即使在声明它们之前,它们也可以在其封闭范围内访问,但是它们的值是undefined在到达声明语句之前:

shell
function checkHoisting() { console.log(foo); // undefined var foo = "Foo"; console.log(foo); // Foo } checkHoisting();

运行代码片段Hide results

展开片段

let variables are hoisted but not initialized until their definition is evaluated. Accessing them before the initialization results in a ReferenceError. The variable is said to be in the temporal dead zone from the start of the block until the declaration statement is processed.

shell
function checkHoisting() { console.log(foo); // ReferenceError let foo = "Foo"; console.log(foo); // Foo } checkHoisting();

Run code snippetHide results

Expand snippet

Creating global object property

At the top level, let, unlike var, does not create a property on the global object:

shell
var foo = "Foo"; // globally scoped let bar = "Bar"; // globally scoped but not part of the global object console.log(window.foo); // Foo console.log(window.bar); // undefined

Run code snippetHide results

Expand snippet

Redeclaration

In strict mode, var will let you re-declare the same variable in the same scope while let raises a SyntaxError.

shell
'use strict'; var foo = "foo1"; var foo = "foo2"; // No problem, 'foo1' is replaced with 'foo2'. let bar = "bar1"; let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

Run code snippetHide results

Expand snippet

2024年6月29日 12:07 回复

let can also be used to avoid problems with closures. It binds fresh value rather than keeping an old reference as shown in examples below.

shell
for(var i=1; i<6; i++) { $("#div" + i).click(function () { console.log(i); }); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <p>Clicking on each number will log to console:</p> <div id="div1">1</div> <div id="div2">2</div> <div id="div3">3</div> <div id="div4">4</div> <div id="div5">5</div>

Run code snippetHide results

Expand snippet

Code above demonstrates a classic JavaScript closure problem. Reference to the i variable is being stored in the click handler closure, rather than the actual value of i.

Every single click handler will refer to the same object because there’s only one counter object which holds 6 so you get six on each click.

A general workaround is to wrap this in an anonymous function and pass i as an argument. Such issues can also be avoided now by using let instead var as shown in the code below.

(Tested in Chrome and Firefox 50)

shell
for(let i=1; i<6; i++) { $("#div" + i).click(function () { console.log(i); }); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <p>Clicking on each number will log to console:</p> <div id="div1">1</div> <div id="div2">2</div> <div id="div3">3</div> <div id="div4">4</div> <div id="div5">5</div>

Run code snippetHide results

Expand snippet

2024年6月29日 12:07 回复

What's the difference between let and var?

  • A variable defined using a var statement is known throughout the function it is defined in, from the start of the function. (*)
  • A variable defined using a let statement is only known in the block it is defined in, from the moment it is defined onward. (**)

To understand the difference, consider the following code:

shell
// i IS NOT known here // j IS NOT known here // k IS known here, but undefined // l IS NOT known here function loop(arr) { // i IS known here, but undefined // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here for( var i = 0; i < arr.length; i++ ) { // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here }; // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here for( let j = 0; j < arr.length; j++ ) { // i IS known here, and has a value // j IS known here, and has a value // k IS known here, but has a value only the second time loop is called // l IS NOT known here }; // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here } loop([1,2,3,4]); for( var k = 0; k < arr.length; k++ ) { // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS NOT known here }; for( let l = 0; l < arr.length; l++ ) { // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS known here, and has a value }; loop([1,2,3,4]); // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS NOT known here

Here, we can see that our variable j is only known in the first for loop, but not before and after. Yet, our variable i is known in the entire function.

Also, consider that block scoped variables are not known before they are declared because they are not hoisted. You're also not allowed to redeclare the same block scoped variable within the same block. This makes block scoped variables less error prone than globally or functionally scoped variables, which are hoisted and which do not produce any errors in case of multiple declarations.


Is it safe to use let today?

Some people would argue that in the future we'll ONLY use let statements and that var statements will become obsolete. JavaScript guru Kyle Simpson wrote a very elaborate article on why he believes that won't be the case.

Today, however, that is definitely not the case. In fact, we need actually to ask ourselves whether it's safe to use the let statement. The answer to that question depends on your environment:

  • If you're writing server-side JavaScript code (Node.js), you can safely use the let statement.

  • If you're writing client-side JavaScript code and use a browser based transpiler (like Traceur or babel-standalone), you can safely use the let statement, however your code is likely to be anything but optimal with respect to performance.

  • If you're writing client-side JavaScript code and use a Node based transpiler (like the traceur shell script or Babel), you can safely use the let statement. And, because your browser will only know about the transpiled code, performance drawbacks should be limited.

  • If you're writing client-side JavaScript code and don't use a transpiler, you need to consider browser support.

    There are still some browsers that don't support let at all :

在此输入图像描述


How to keep track of browser support

For an up-to-date overview of which browsers support the let statement at the time of your reading this answer, see this Can I Use page.


(*) Globally and functionally scoped variables can be initialized and used before they are declared because JavaScript variables are hoisted. This means that declarations are always moved to the top of the scope.

(**) Block scoped variables are not hoisted

2024年6月29日 12:07 回复

Here's an explanation of the let keyword with some examples.

let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function

This table on Wikipedia shows which browsers support Javascript 1.7.

Note that only Mozilla and Chrome browsers support it. IE, Safari, and potentially others don't.

2024年6月29日 12:07 回复

let

Block scope

Variables declared using the let keyword are block-scoped, which means that they are available only in the block in which they were declared.

At the top level (outside of a function)

At the top level, variables declared using let don't create properties on the global object.

shell
var globalVariable = 42; let blockScopedVariable = 43; console.log(globalVariable); // 42 console.log(blockScopedVariable); // 43 console.log(this.globalVariable); // 42 console.log(this.blockScopedVariable); // undefined

Inside a function

Inside a function (but outside of a block), let has the same scope as var.

shell
(() => { var functionScopedVariable = 42; let blockScopedVariable = 43; console.log(functionScopedVariable); // 42 console.log(blockScopedVariable); // 43 })(); console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Inside a block

Variables declared using let inside a block can't be accessed outside that block.

shell
{ var globalVariable = 42; let blockScopedVariable = 43; console.log(globalVariable); // 42 console.log(blockScopedVariable); // 43 } console.log(globalVariable); // 42 console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Inside a loop

Variables declared with let in loops can be referenced only inside that loop.

shell
for (var i = 0; i < 3; i++) { var j = i * 2; } console.log(i); // 3 console.log(j); // 4 for (let k = 0; k < 3; k++) { let l = k * 2; } console.log(typeof k); // undefined console.log(typeof l); // undefined // Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Loops with closures

If you use let instead of var in a loop, with each iteration you get a new variable. That means that you can safely use a closure inside a loop.

shell
// Logs 3 thrice, not what we meant. for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // Logs 0, 1 and 2, as expected. for (let j = 0; j < 3; j++) { setTimeout(() => console.log(j), 0); }

Temporal dead zone

Because of the temporal dead zone, variables declared using let can't be accessed before they are declared. Attempting to do so throws an error.

shell
console.log(noTDZ); // undefined var noTDZ = 43; console.log(hasTDZ); // ReferenceError: hasTDZ is not defined let hasTDZ = 42;

No re-declaring

You can't declare the same variable multiple times using let. You also can't declare a variable using let with the same identifier as another variable which was declared using var.

shell
var a; var a; // Works fine. let b; let b; // SyntaxError: Identifier 'b' has already been declared var c; let c; // SyntaxError: Identifier 'c' has already been declared

const

const is quite similar to let—it's block-scoped and has TDZ. There are, however, two things which are different.

No re-assigning

Variable declared using const can't be re-assigned.

shell
const a = 42; a = 43; // TypeError: Assignment to constant variable.

Note that it doesn't mean that the value is immutable. Its properties still can be changed.

shell
const obj = {}; obj.a = 42; console.log(obj.a); // 42

If you want to have an immutable object, you should use Object.freeze().

shell
const obj = Object.freeze({a: 40}); obj.a = 42; console.log(obj.a); // 40 console.log(obj.b); // undefined

Initializer is required

You always must specify a value when declaring a variable using const.

shell
const a; // SyntaxError: Missing initializer in const declaration
2024年6月29日 12:07 回复

The accepted answer is missing a point:

shell
{ let a = 123; }; console.log(a); // ReferenceError: a is not defined
2024年6月29日 12:07 回复

In most basic terms,

shell
for (let i = 0; i < 5; i++) { // i accessible ✔️ } // i not accessible ❌

shell
for (var i = 0; i < 5; i++) { // i accessible ✔️ } // i accessible ✔️

2024年6月29日 12:07 回复

Here is an example of the difference between the two:

在此输入图像描述

As you can see, the var j variable still has a value outside the for loop scope (Block Scope), but the let i variable is undefined outside of the for loop scope.

shell
"use strict"; console.log("var:"); for (var j = 0; j < 2; j++) { console.log(j); } console.log(j); console.log("let:"); for (let i = 0; i < 2; i++) { console.log(i); } console.log(i);

Run code snippetHide results

Expand snippet

2024年6月29日 12:07 回复

The main difference is the scope difference, while let can be only available inside the scope it's declared, like in for loop, var can be accessed outside the loop for example. From the documentation in MDN (examples also from MDN):

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

Variables declared by let have as their scope the block in which they are defined, as well as in any contained sub-blocks. In this way, let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function:

shell
function varTest() { var x = 1; if (true) { var x = 2; // same variable! console.log(x); // 2 } console.log(x); // 2 } function letTest() { let x = 1; if (true) { let x = 2; // different variable console.log(x); // 2 } console.log(x); // 1 }`

At the top level of programs and functions, let, unlike var, does not create a property on the global object. For example:

shell
var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(this.y); // undefined

When used inside a block, let limits the variable's scope to that block. Note the difference between var whose scope is inside the function where it is declared.

shell
var a = 1; var b = 2; if (a === 1) { var a = 11; // the scope is global let b = 22; // the scope is inside the if-block console.log(a); // 11 console.log(b); // 22 } console.log(a); // 11 console.log(b); // 2

Also don't forget it's ECMA6 feature, so it's not fully supported yet, so it's better always transpiles it to ECMA5 using Babel etc... for more info about visit babel website

2024年6月29日 12:07 回复

There are some subtle differences — let scoping behaves more like variable scoping does in more or less any other languages.

e.g. It scopes to the enclosing block, They don't exist before they're declared, etc.

However it's worth noting that let is only a part of newer Javascript implementations and has varying degrees of browser support.

2024年6月29日 12:07 回复
  • Variable Not Hoisting

    let will not hoist to the entire scope of the block they appear in. By contrast, var could hoist as below.

    shell
    { console.log(cc); // undefined. Caused by hoisting var cc = 23; } { console.log(bb); // ReferenceError: bb is not defined let bb = 23; }

    Actually, Per @Bergi, Both var and let are hoisted.

  • Garbage Collection

    Block scope of let is useful relates to closures and garbage collection to reclaim memory. Consider,

    shell
    function process(data) { //... } var hugeData = { .. }; process(hugeData); var btn = document.getElementById("mybutton"); btn.addEventListener( "click", function click(evt){ //.... });

    The click handler callback does not need the hugeData variable at all. Theoretically, after process(..) runs, the huge data structure hugeData could be garbage collected. However, it's possible that some JS engine will still have to keep this huge structure, since the click function has a closure over the entire scope.

    However, the block scope can make this huge data structure to garbage collected.

    shell
    function process(data) { //... } { // anything declared inside this block can be garbage collected let hugeData = { .. }; process(hugeData); } var btn = document.getElementById("mybutton"); btn.addEventListener( "click", function click(evt){ //.... });
  • let loops

    let in the loop can re-binds it to each iteration of the loop, making sure to re-assign it the value from the end of the previous loop iteration. Consider,

    shell
    // print '5' 5 times for (var i = 0; i < 5; ++i) { setTimeout(function () { console.log(i); }, 1000); }

    However, replace var with let

    shell
    // print 1, 2, 3, 4, 5. now for (let i = 0; i < 5; ++i) { setTimeout(function () { console.log(i); }, 1000); }

    Because let create a new lexical environment with those names for a) the initialiser expression b) each iteration (previosly to evaluating the increment expression), more details are here.

2024年6月29日 12:07 回复

The difference is in the scope of the variables declared with each.

In practice, there are a number of useful consequences of the difference in scope:

  1. let variables are only visible in their nearest enclosing block ({ ... }).
  2. let variables are only usable in lines of code that occur after the variable is declared (even though they are hoisted!).
  3. let variables may not be redeclared by a subsequent var or let.
  4. Global let variables are not added to the global window object.
  5. let variables are easy to use with closures (they do not cause race conditions).

The restrictions imposed by let reduce the visibility of the variables and increase the likelihood that unexpected name collisions will be found early. This makes it easier to track and reason about variables, including their reachability(helping with reclaiming unused memory).

Consequently, let variables are less likely to cause problems when used in large programs or when independently-developed frameworks are combined in new and unexpected ways.

var may still be useful if you are sure you want the single-binding effect when using a closure in a loop (#5) or for declaring externally-visible global variables in your code (#4). Use of var for exports may be supplanted if export migrates out of transpiler space and into the core language.

Examples

1. No use outside nearest enclosing block: This block of code will throw a reference error because the second use of x occurs outside of the block where it is declared with let:

shell
{ let x = 1; } console.log(`x is ${x}`); // ReferenceError during parsing: "x is not defined".

In contrast, the same example with var works.

2. No use before declaration:
This block of code will throw a ReferenceError before the code can be run because x is used before it is declared:

shell
{ x = x + 1; // ReferenceError during parsing: "x is not defined". let x; console.log(`x is ${x}`); // Never runs. }

In contrast, the same example with var parses and runs without throwing any exceptions.

3. No redeclaration: The following code demonstrates that a variable declared with let may not be redeclared later:

shell
let x = 1; let x = 2; // SyntaxError: Identifier 'x' has already been declared

4. Globals not attached to window:

shell
var button = "I cause accidents because my name is too common."; let link = "Though my name is common, I am harder to access from other JS files."; console.log(link); // OK console.log(window.link); // undefined (GOOD!) console.log(window.button); // OK

5. Easy use with closures: Variables declared with var do not work well with closures inside loops. Here is a simple loop that outputs the sequence of values that the variable i has at different points in time:

shell
for (let i = 0; i < 5; i++) { console.log(`i is ${i}`), 125/*ms*/); }

Specifically, this outputs:

shell
i is 0 i is 1 i is 2 i is 3 i is 4

In JavaScript we often use variables at a significantly later time than when they are created. When we demonstrate this by delaying the output with a closure passed to setTimeout:

shell
for (let i = 0; i < 5; i++) { setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/); }

... the output remains unchanged as long as we stick with let. In contrast, if we had used var i instead:

shell
for (var i = 0; i < 5; i++) { setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/); }

... the loop unexpectedly outputs "i is 5" five times:

shell
i is 5 i is 5 i is 5 i is 5 i is 5
2024年6月29日 12:07 回复

Here's an example to add on to what others have already written. Suppose you want to make an array of functions, adderFunctions, where each function takes a single Number argument and returns the sum of the argument and the function's index in the array. Trying to generate adderFunctions with a loop using the var keyword won't work the way someone might naïvely expect:

shell
// An array of adder functions. var adderFunctions = []; for (var i = 0; i < 1000; i++) { // We want the function at index i to add the index to its argument. adderFunctions[i] = function(x) { // What is i bound to here? return x + i; }; } var add12 = adderFunctions[12]; // Uh oh. The function is bound to i in the outer scope, which is currently 1000. console.log(add12(8) === 20); // => false console.log(add12(8) === 1008); // => true console.log(i); // => 1000 // It gets worse. i = -8; console.log(add12(8) === 0); // => true

The process above doesn't generate the desired array of functions because i's scope extends beyond the iteration of the for block in which each function was created. Instead, at the end of the loop, the i in each function's closure refers to i's value at the end of the loop (1000) for every anonymous function in adderFunctions. This isn't what we wanted at all: we now have an array of 1000 different functions in memory with exactly the same behavior. And if we subsequently update the value of i, the mutation will affect all the adderFunctions.

However, we can try again using the let keyword:

shell
// Let's try this again. // NOTE: We're using another ES6 keyword, const, for values that won't // be reassigned. const and let have similar scoping behavior. const adderFunctions = []; for (let i = 0; i < 1000; i++) { // NOTE: We're using the newer arrow function syntax this time, but // using the "function(x) { ..." syntax from the previous example // here would not change the behavior shown. adderFunctions[i] = x => x + i; } const add12 = adderFunctions[12]; // Yay! The behavior is as expected. console.log(add12(8) === 20); // => true // i's scope doesn't extend outside the for loop. console.log(i); // => ReferenceError: i is not defined

This time, i is rebound on each iteration of the for loop. Each function now keeps the value of i at the time of the function's creation, and adderFunctions behaves as expected.

Now, image mixing the two behaviors and you'll probably see why it's not recommended to mix the newer let and const with the older var in the same script. Doing so can result is some spectacularly confusing code.

shell
const doubleAdderFunctions = []; for (var i = 0; i < 1000; i++) { const j = i; doubleAdderFunctions[i] = x => x + i + j; } const add18 = doubleAdderFunctions[9]; const add24 = doubleAdderFunctions[12]; // It's not fun debugging situations like this, especially when the // code is more complex than in this example. console.log(add18(24) === 42); // => false console.log(add24(18) === 42); // => false console.log(add18(24) === add24(18)); // => false console.log(add18(24) === 2018); // => false console.log(add24(18) === 2018); // => false console.log(add18(24) === 1033); // => true console.log(add24(18) === 1030); // => true

Don't let this happen to you. Use a linter.

NOTE: This is a teaching example intended to demonstrate the var/let behavior in loops and with function closures that would also be easy to understand. This would be a terrible way to add numbers. But the general technique of capturing data in anonymous function closures might be encountered in the real world in other contexts. YMMV.

2024年6月29日 12:07 回复

The explanation is taken from the article I wrote at Medium:

Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope by the parser which reads the source code into an intermediate representation before the actual code execution starts by the JavaScript interpreter. So, it actually doesn’t matter where variables or functions are declared, they will be moved to the top of their scope regardless of whether their scope is global or local. This means that

shell
console.log (hi); var hi = "say hi";

is actually interpreted to

shell
var hi = undefined; console.log (hi); hi = "say hi";

So, as we saw just now, var variables are being hoisted to the top of their scope and are being initialized with the value of undefined which means that we can actually assign their value before actually declaring them in the code like so:

shell
hi = “say hi” console.log (hi); // say hi var hi;

Regarding function declarations, we can invoke them before actually declaring them like so:

shell
sayHi(); // Hi function sayHi() { console.log('Hi'); };

Function expressions, on the other hand, are not hoisted, so we’ll get the following error:

shell
sayHi(); //Output: "TypeError: sayHi is not a function var sayHi = function() { console.log('Hi'); };

ES6 introduced JavaScript developers the let and const keywords. While let and const are block-scoped and not function scoped as var it shouldn’t make a difference while discussing their hoisting behavior. We’ll start from the end, JavaScript hoists let and const.

shell
console.log(hi); // Output: Cannot access 'hi' before initialization let hi = 'Hi';

As we can see above, let doesn’t allow us to use undeclared variables, hence the interpreter explicitly output a reference error indicating that the hi variable cannot be accessed before initialization. The same error will occur if we change the above let to const

shell
console.log(hi); // Output: Cannot access 'hi' before initialization const hi = 'Hi';

So, bottom line, the JavaScript parser searches for variable declarations and functions and hoists them to the top of their scope before code execution and assign values to them in the memory so in case the interpreter will encounter them while executing the code he will recognize them and will be able to execute the code with their assigned values. Variables declared with let or const remain uninitialized at the beginning of execution while that variables declared with var are being initialized with a value of undefined.

I added this visual illustration to better help understanding of how are the hoisted variables and function are being saved in the memory

在此输入图像描述

2024年6月29日 12:07 回复

Function VS block scope:

The main difference between var and let is that variables declared with var are function scoped. Whereas functions declared with let are block scoped. For example:

shell
function testVar () { if(true) { var foo = 'foo'; } console.log(foo); } testVar(); // logs 'foo' function testLet () { if(true) { let bar = 'bar'; } console.log(bar); } testLet(); // reference error // bar is scoped to the block of the if statement

variables with var:

When the first function testVar gets called the variable foo, declared with var, is still accessible outside the if statement. This variable foo would be available everywhere within the scope of the testVar function.

variables with let:

When the second function testLet gets called the variable bar, declared with let, is only accessible inside the if statement. Because variables declared with let are block scoped (where a block is the code between curly brackets e.g if{} , for{}, function{}).

let variables don't get hoisted:

Another difference between var and let is variables with declared with let don't get hoisted. An example is the best way to illustrate this behavior:

variables with let don't get hoisted:

shell
console.log(letVar); let letVar = 10; // referenceError, the variable doesn't get hoisted

variables with var do get hoisted:

shell
console.log(varVar); var varVar = 10; // logs undefined, the variable gets hoisted

Global let doesn't get attached to window:

A variable declared with let in the global scope (which is code that is not in a function) doesn't get added as a property on the global window object. For example (this code is in global scope):

shell
var bar = 5; let foo = 10; console.log(bar); // logs 5 console.log(foo); // logs 10 console.log(window.bar); // logs 5, variable added to window object console.log(window.foo); // logs undefined, variable not added to window object

When should let be used over var?

Use let over var whenever you can because it is simply scoped more specific. This reduces potential naming conflicts which can occur when dealing with a large number of variables. var can be used when you want a global variable explicitly to be on the window object (always consider carefully if this is really necessary).

2024年6月29日 12:07 回复

It also appears that, at least in Visual Studio 2015, TypeScript 1.5, "var" allows multiple declarations of the same variable name in a block, and "let" doesn't.

This won't generate a compile error:

shell
var x = 1; var x = 2;

This will:

shell
let x = 1; let x = 2;
2024年6月29日 12:07 回复

When Using let

The let keyword attaches the variable declaration to the scope of whatever block (commonly a { .. } pair) it's contained in. In other words,let implicitly hijacks any block's scope for its variable declaration.

let variables cannot be accessed in the window object because they cannot be globally accessed.

shell
function a(){ { // this is the Max Scope for let variable let x = 12; } console.log(x); } a(); // Uncaught ReferenceError: x is not defined

When Using var

var and variables in ES5 has scopes in functions meaning the variables are valid within the function and not outside the function itself.

var variables can be accessed in the window object because they cannot be globally accessed.

shell
function a(){ // this is the Max Scope for var variable { var x = 12; } console.log(x); } a(); // 12

If you want to know more continue reading below

one of the most famous interview questions on scope also can suffice the exact use of let and var as below;

When using let

shell
for (let i = 0; i < 10 ; i++) { setTimeout( function a() { console.log(i); //print 0 to 9, that is literally AWW!!! }, 100 * i); }

This is because when using let, for every loop iteration the variable is scoped and has its own copy.

When using var

shell
for (var i = 0; i < 10 ; i++) { setTimeout( function a() { console.log(i); //print 10 times 10 }, 100 * i); }

This is because when using var, for every loop iteration the variable is scoped and has shared copy.

2024年6月29日 12:07 回复

I just came across one use case that I had to use var over let to introduce new variable. Here's a case:

I want to create a new variable with dynamic variable names.

shell
let variableName = 'a'; eval("let " + variableName + '= 10;'); console.log(a); // this doesn't work var variableName = 'a'; eval("var " + variableName + '= 10;'); console.log(a); // this works

The above code doesn't work because eval introduces a new block of code. The declaration using var will declare a variable outside of this block of code since var declares a variable in the function scope.

let, on the other hand, declares a variable in a block scope. So, a variable will only be visible in eval block.

2024年6月29日 12:07 回复

Now I think there is better scoping of variables to a block of statements using let:

shell
function printnums() { // i is not accessible here for(let i = 0; i <10; i+=) { console.log(i); } // i is not accessible here // j is accessible here for(var j = 0; j <10; j++) { console.log(j); } // j is accessible here }

I think people will start using let here after so that they will have similar scoping in JavaScript like other languages, Java, C#, etc.

People with not a clear understanding about scoping in JavaScript used to make the mistake earlier.

Hoisting is not supported using let.

With this approach errors present in JavaScript are getting removed.

Refer to ES6 In Depth: let and const to understand it better.

2024年6月29日 12:07 回复

你的答案