范围规则
主要区别是作用域规则。用
var关键字声明的变量的作用域为立即函数主体(因此作用域为函数),而
let变量的作用域为由表示的立即 封闭 块
{}(因该块作用域)。function run() { var foo = "Foo"; let bar = "Bar"; console.log(foo, bar); { let baz = "Bazz"; console.log(baz); } console.log(baz); // ReferenceError}run();将
let关键字引入语言的原因是函数范围令人困惑,并且是Javascript中错误的主要来源之一。
看一下另一个stackoverflow问题的示例:
var funcs = [];// let's create 3 functionsfor (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``funcs[j]();由于匿名函数绑定到同一变量,因此每次调用时都会输出到控制台。
人们必须创建立即调用的函数以从循环中捕获正确的值,但这也很麻烦。
Hoisting
尽管用
var关键字声明的变量被“提升”到块的顶部,这意味着即使在声明它们之前,也可以在其封闭范围内访问它们:
function run() { console.log(foo); // undefined var foo = "Foo"; console.log(foo); // Foo}run();let变量必须在定义定义后才能初始化。在初始化之前访问它们会导致
ReferenceError。从块的开始直到初始化处理之前,变量都处于“临时死区”中。
function checkHoisting() { console.log(foo); // ReferenceError let foo = "Foo"; console.log(foo); // Foo}checkHoisting();创建全局对象属性
在顶层
let,与不同
var,不会在全局对象上创建属性:
var foo = "Foo"; // globally scopedlet bar = "Bar"; // globally scopedconsole.log(window.foo); // Fooconsole.log(window.bar); // undefined
重新声明
在严格模式下,
var将在
let引发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



