《JavaScript高级程序设计》学习笔记(一)- var、let 和 const

变量声明 ECMAScript 变量是松散类型的,变量可以用于保存任何类型的数据,每个变量只不过是一个用于保存任意值的命名占位符。有三个关键字可以声明变量:varletconst。其中var在所有版本中都可以使用,而letconst只能在 ECMAScript6 及之后版本中使用。
1. var关键字

var message

定义一个名为message的变量,可以用于保存任何类型的值。在不初始化的情况下,变量会保存一个特殊值undefined
var message = 'hi' message = 100 // 合法,但不推荐

在声明的同时可以进行初始化。变量的初始化只是简单的赋值,并不标识变量类型,之后不仅可以改变变量保存的值,还可以改变值的类型。
1.1 var声明作用域 使用var操作符在全局作用域中声明的变量将成为window对象的属性。
var name = 'Stan' console.log(window.name) // Stan

使用var操作符定义的变量会成为包含它的函数的局部变量。
function test() { var message = 'h1' // 局部变量 } test() // 函数调用之后其中的局部变量即被销毁 console.log(message) // error

在函数内定义变量时省略var操作符,将创建一个全局变量。(在严格模式下将抛出ReferenceError
function test() { message = 'hi' // 全局变量 } test() console.log(message) // hi

可以在一条语句中定义多个变量,并进行初始化(可选的)。
var message = 'hi', age = 20, found = false

1.2 var声明提升 使用var操作符声明的变量会自动提升到函数作用域的顶部。变量提升(hoist)指的是将变量声明提升到函数作用域的顶部。
function foo() { console.log(age) var age = 20 } foo() // undefined/* 等价于 */ function foo() { var age console.log(age) age = 20 }

【《JavaScript高级程序设计》学习笔记(一)- var、let 和 const】此外,可以多次使用var声明同一个变量,而letconst均不允许在作用域内出现冗余声明。混用三个操作符也要遵从操作符的规则。
var age = 20 var age = 21 var age = 22 console.log(age) // 22let name let name // SyntaxErrorvar name = 'xiaoming' var name = 'xiaohong' // OK let name // SyntaxErrorlet age var age // SyntaxError

2. let关键字
letvar的作用类似,主要区别在于,let声明的范围是块作用域,而var声明的范围是函数作用域。
if (true) { var name = 'Stan' console.log(name) // Stan } console.log(name) // Stanif (true) { let age = 20 // 作用域仅限于当前块 console.log(age) // 20 } console.log(age) // ReferenceError

JavaScript 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同标识符不会报错,因为同一个块中没有重复声明。
var name = 'xiaoming' let age = 20 console.log(name) // xiaoming console.log(age) // 20 if (true) { var name = 'xiaohong' let age = 19 console.log(name) // xiaohong console.log(age) // 19 }

2.1 暂时性死区 letvar的另一个重要区别在于,let声明的变量不会在作用域内被提升。
console.log(name) // undefined console.log(age) // ReferenceError var name = 'xiaoming' let age = 20

在解析代码时,JavaScript 引擎也会注意到出现在块后部的let声明,但在此之前不能以任何方式来引用未声明的变量,否则将抛出ReferenceError。在let声明前的执行瞬间称为暂时性死区(temporal dead zone)。
2.2 全局声明 与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性。
let age = 10 console.log(window.age) // undefined

2.3 条件声明 JavaScript 不支持条件声明。

使用try/catch语句或typeof操作符也无法解决,因为条件块中let声明的作用域仅限于该块。
if (typeof name === 'undefined') { let name // name的作用域仅限于此块作用域 } name = 'Stan' // 无法达到目的,形同全局赋值 try { console.log(age) // 若未声明age,则会报错 } catch (error) { let age // age的作用域仅限于此块作用域 } age = 20 // 无法达到目的,形同全局赋值

2.4 for循环中的let声明(包括for-infor-of循环)
for (var i = 0; i < 5; i++) {} console.log(i) // 5 for (var j = 0; j < 5; j++) { setTimeout(() => console.log(j)) } // 5 5 5 5 5 for (let m = 0; m < 5; m++) {} console.log(m) // ReferenceError for (let n = 0; n < 5; n++) { setTimeout(() => console.log(n)) } // 1 2 3 4 5

3. const关键字
const关键字与let基本相同,唯一重要的区别在于使用const关键字声明时必须同时初始化变量,且不能修改该变量的值,否则将抛出SyntaxError
const声明的变量只适用于它指向的变量的引用,即若const变量引用一个对象,修改该对象内部的属性并不违反const的限制。
4. 声明风格及最佳实践
const优先,let次之,不使用var

    推荐阅读