概览
ES6 新增了两个定义变量的关键字:let
与 const
,它们简直取代了 ES5 定义变量的形式:var
。let
是新的var
,const
简略的常量申明。
function f() { { let x; { // okay, block scoped name const x = "sneaky"; // error, const x = "foo"; } // error, already declared in block let x = "inner"; }}
let
、const
实现块级作用域
let
,const
创立的变量都是块级作用域:它们只存在突围它们的最深代码块中。
function func() { if (true) { let tmp = 123; // const tmp = 123; } console.log(tmp); // ReferenceError: tmp is not defined}console.log(tmp);// ReferenceError: tmp is not defined
相比之下,var
申明的是函数域。
function func() { if (true) { var tmp = 123; } console.log(tmp); // 123}func()console.log(tmp); // tmp is not defined
面试题:循环中定时器闭包
for(var i = 0; i < 5; i++) { setTimeout(() => { console.log(i) //5, 5, 5, 5, 5 }, 0)}console.log(i) //5 i跳出循环体净化内部函数//将var改成let之后for(let i = 0; i < 5; i++) { setTimeout(() => { console.log(i) // 0,1,2,3,4 }, 0)}console.log(i)//i is not defined i无奈净化内部函数
在for循环中应用var申明的循环变量,会跳出循环体净化以后的函数。
let
、const
暂时性死区(temporal dead zone)
let
,const
申明的变量领有暂时性死区:当进入它的作用域,它不能被拜访(获取或设置)直到执行达到申明。
简略形容:
if (true) { //这块区域是TDZ console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization let a = 1 // const a = 1}
if (true) { // enter new scope, TDZ starts // Uninitialized binding for `tmp` is created tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ ends, `tmp` is initialized with `undefined` console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123}
上面示例将演示死区(dead zone)是真正短暂工夫的(基于工夫)和不受空间条件限度(基于地位)
if (true) { // enter new scope, TDZ starts const func = function () { console.log(myVar); // OK! }; // Here we are within the TDZ and // accessing `myVar` would cause a `ReferenceError` let myVar = 3; // TDZ ends func(); // called outside TDZ}
var
变量晋升
JavaScript中,咱们通常说的作用域是函数作用域,应用var申明的变量,无论是在代码的哪个中央申明的,都会晋升到以后作用域的最顶部,这种行为叫做变量晋升(Hoisting)
上面代码,演示了函数的变量晋升:
{ // Enter a new scope console.log(foo()); // hello, due to hoisting function foo() { return 'hello'; }}
也就是说,如果在函数外部申明的变量,都会被晋升到函数结尾,而在全局的申明,就会晋升到全局作用域的顶部。
function test() { console.log('1: ', a) //undefined if (false) { var a = 1 } console.log('3: ', a) //undefined}test()
理论执行时,下面的代码中的变量a会晋升到函数顶部申明,即便if语句的条件是false,也一样不影响a的晋升。
function test() { var a //a申明没有赋值 console.log('1: ', a) //undefined if (false) { a = 1 } //a申明没有赋值 console.log('3: ', a) //undefined}
在嵌套函数的状况,变量只会晋升到最近一个函数的顶部,而不会到内部函数。
//b晋升到函数a顶部,但不会晋升到函数test。function test() { function a() { if (false) { var b = 2 } } console.log('b: ', b)}test() //b is not defined
let
不容许反复申明
let
不容许在雷同作用域内,反复申明同一个变量。
// 报错function func() { let a = 10; var a = 1;}// 报错function func() { let a = 10; let a = 1;}
因而在函数外部不能从新申明函数
function func(arg) { let arg;}func() // 报错 Identifier 'arg' has already been declaredfunction func(arg) { { let arg; }}func() // 不报错
const
命令
个别应用场景:
const start = 'hi all';const getName = () => { return 'jelly';};const conf = { fav: 'Coding'};// 模板const msg = `${start}, my name is ${getName()}, ${conf.fav} is my favourite`;
你可能不晓得的事:
// 1. 与引号混用const wantToSay = `I'm a "tbfed"`;// 2. 反对多行文本const slogan = `I have a dream today!`;// 比拟适宜写HTMLconst resultTpl = ` <section> <div>...</div> </section>`;
var
、let
、const
有什么区别
- 相同点:
var
,let
,const
申明的变量,是不能被delete
的; - 区别:
变量晋升:var
申明的变量存在变量晋升,即变量能够在申明之前调用,值为undefined;let
,const
不存在变量晋升,即它们申明的变量肯定要在申明后应用,否则会报错。
暂时性死区:var
不存在暂时性死区;let
、const
存在暂时性死区,只有等申明变量后,才能够获取和应用该变量。
反复申明:var
容许反复申明;lat
、const
在同一作用域不容许反复申明。
批改申明的变量:var
和let
能够批改申明的变量;const
申明一个只读常量,一旦申明,常量的值就不能扭转。
var/let/const、块级作用域、TDZ、变量晋升