What's the difference between using “let” and “var” to declare a variable in JavaScript?
What's the difference between using “let” and “var”?
ECMAScript 6 introduced the let
statement.
I've heard that it's described as a local
variable, but I'm still not quite sure how it behaves differently than the var
keyword.
What are the differences?. When should let
be used instead of var
?
回答1
The difference is scoping. var
is scoped to the nearest function block and let
is scoped to the nearest enclosing block, which can be smaller than a function block. Both are global if outside any block.
Also, variables declared with let
are not accessible before they are declared in their enclosing block. As seen in the demo, this will throw a ReferenceError exception.
var html = ''; write('#### global ####\n'); write('globalVar: ' + globalVar); //undefined, but visible try { write('globalLet: ' + globalLet); //undefined, *not* visible } catch (exception) { write('globalLet: exception'); } write('\nset variables'); var globalVar = 'globalVar'; let globalLet = 'globalLet'; write('\nglobalVar: ' + globalVar); write('globalLet: ' + globalLet); function functionScoped() { write('\n#### function ####'); write('\nfunctionVar: ' + functionVar); //undefined, but visible try { write('functionLet: ' + functionLet); //undefined, *not* visible } catch (exception) { write('functionLet: exception'); } write('\nset variables'); var functionVar = 'functionVar'; let functionLet = 'functionLet'; write('\nfunctionVar: ' + functionVar); write('functionLet: ' + functionLet); } function blockScoped() { write('\n#### block ####'); write('\nblockVar: ' + blockVar); //undefined, but visible try { write('blockLet: ' + blockLet); //undefined, *not* visible } catch (exception) { write('blockLet: exception'); } for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) { write('\nblockVar: ' + blockVar); // visible here and whole function }; for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) { write('blockLet: ' + blockLet); // visible only here }; write('\nblockVar: ' + blockVar); try { write('blockLet: ' + blockLet); //undefined, *not* visible } catch (exception) { write('blockLet: exception'); } } function write(line) { html += (line ? line : '') + '<br />'; } functionScoped(); blockScoped(); document.getElementById('results').innerHTML = html;
Global:
They are very similar when used like this outside a function block.
let me = 'go'; // globally scoped
var i = 'able'; // globally scoped
However, global variables defined with let
will not be added as properties on the global window
object like those defined with var
.
console.log(window.me); // undefined
console.log(window.i); // 'able'
Function:
They are identical when used like this in a function block.
function ingWithinEstablishedParameters() {
let terOfRecommendation = 'awesome worker!'; //function block scoped
var sityCheerleading = 'go!'; //function block scoped
}
Block:
Here is the difference. let
is only visible in the for()
loop and var
is visible to the whole function.
unction allyIlliterate() { //tuce is *not* visible out here for( let tuce = 0; tuce < 5; tuce++ ) { //tuce is only visible in here (and in the for() parentheses) //and there is a separate tuce variable for each iteration of the loop } //tuce is *not* visible out here } function byE40() { //nish *is* visible out here for( var nish = 0; nish < 5; nish++ ) { //nish is visible to the whole function } //nish *is* visible out here }
Redeclaration:
Assuming strict mode, var
will let you re-declare the same variable in the same scope. On the other hand, let
will not:
'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
回答1的新版本
Scoping rules
Main difference is scoping rules. Variables declared by var
keyword are scoped to the immediate function body (hence the function scope) while let
variables are scoped to the immediate enclosing block denoted by { }
(hence the block scope).
function run() { var foo = "Foo"; let bar = "Bar"; console.log(foo, bar); // Foo Bar { let baz = "Bazz"; console.log(baz); // Bazz } console.log(baz); // ReferenceError } run();
The reason why let
keyword was introduced to the language was function scope is confusing and was one of the main sources of bugs in JavaScript.
Take a look at this example from another stackoverflow question:
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](); }
My value: 3
was output to console each time funcs[j]();
was invoked since anonymous functions were bound to the same variable.
People had to create immediately invoked functions to capture correct value from the loops but that was also hairy可怕的.
Hoisting
While variables declared with var
keyword are hoisted (initialized with undefined
before the code is run) which means they are accessible in their enclosing scope even before they are declared:
function run() { console.log(foo); // undefined var foo = "Foo"; console.log(foo); // Foo } run();
let
variables are not initialized until their definition is evaluated. Accessing them before the initialization results in a ReferenceError
. Variable said to be in "temporal dead zone" from the start of the block until the initialization is processed.
function checkHoisting() { console.log(foo); // ReferenceError let foo = "Foo"; console.log(foo); // Foo } checkHoisting();
Creating global object property
At the top level, let
, unlike var
, does not create a property on the global object:
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped
console.log(window.foo); // Foo
console.log(window.bar); // undefined
Redeclaration
In strict mode, var
will let you re-declare the same variable in the same scope while let
raises a SyntaxError.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
回答2
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.
for(var i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
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.
General workaround is to wrap this in an anonymous function and pass i
as argument. Such issues can also be avoided now by using let
instead var
as shown in code below.
'use strict';
for(let i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
作者:Chuck Lu GitHub |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2015-01-13 Covariance and Contravariance (C#)
2015-01-13 Excel导出失败的提示