概述
在JavaScript中有一种变量提升机制 ,即通过var关键字声明的变量,无论在哪里进行声明,都会被当成在当前作用域顶部声明的变量。
尽管这种变量提升机制 作为JavaScript的语法特点之一,会使代码的实现性更加灵活,但如果没有深入了解掌握JavaScript的作用域,那么这种机制就会在开发时给我们造成很多的困扰。因此在ECMAScript 6中引入了块级作用域声明。
let声明
let声明在用法上与var相同,不过let声明的变量不会被提升,可以很轻松的把变量的作用域限制在当前的代码块中。
下面通过简单的代码来演示var与let的区别
// 使用var声明变量
// 函数内部
function changeState(flag) {
if (flag) {
var color = "red"
} else {
// 此处可以访问变量color,其值为undefined
console.log(color)
return null
}
}
changeState(false)
// 块中
{
var a = 1
}
// 此处可以访问变量a, 输出为a = 1
console.log("a = " + a)
// for循环中
for (var i = 0; i < 10; i++) {
}
// 此处可以访问变量i, 输出为i = 10
console.log("i = " + i)
// 使用let声明变量
// 函数内部
function changeState(flag) {
if (flag) {
let color = "red"
} else {
// 此处不能访问变量color,报错:color is not defined
console.log(color)
return null
}
}
changeState(false)
// 块中
{
let a = 1
}
// 此处不能访问变量a,报错:a is not defined
console.log("a = " + a)
// for循环中
for (let i = 0; i < 10; i++) {
}
// 此处不能访问变量i,报错:i is not defined
console.log("i = " + i)
let声明变量不仅能够将作用域限制在块中,还可以防止同一作用域下变量的重复声明。
在不同作用域下重复声明已有标识符
// 声明var变量index
var index = 0
// 再次声明var变量index,ok
var index = 10
// 声明let变量index,报错:Identifier 'index' has already been declared
let index = 100
{
// 在块作用域内声明let变量index,ok
let index = 1000
}
const声明
在ECMAScript 6中还提供了const关键字,用于对常量的声明
通过const关键字声明的常量必须在声明的同时进行初始化
代码示例如下
// 声明的同时进行初始化赋值,ok
const fontSize = 16
// 错误声明
const fontColor
fontColor = "red"
与let类似,在同一作用域下用const声明已经存在的标识符会导致语法错误。
使用const声明的对象,对象本身的绑定不能被修改,但是对象的属性和值是可以修改的
代码示例如下
const person = {
name: "John",
age: "18"
}
// 修改对象属性的值
person.name = "Mark"
person.age = "20"
// 不能修改对象属性,报错:Assignment to constant variable
person = {
name: "Tom"
}
全局块作用域绑定
当我们在全局作用域中使用var声明变量或对象时,该变量或对象将作为浏览器环境中的window对象的属性,这就意味着var很可能会无意中覆盖一个已经存在的全局属性
请看这段代码示例
var greeting = "Welcome"
// 输出“Welcome”
console.log(window.greeting)
// 输出function Screen() { [native code] }
console.log(window.Screen)
var Screen = "ECMAScript 6"
// 输出“ECMAScript 6”
console.log(window.Screen)
上面的代码示例可以看出,greeting被定义为一个全局变量,并立即成为window对象的属性。而定义的全局变量Screen则覆盖了window对象中原有的Screen属性。
如果在全局作用域下使用let或const,则只会在全局作用域下创建一个新的绑定,不会将其作为window对象的属性保存
如下面这段代码
let greeting = "Welcome"
// 输出undefined
console.log(window.greeting)
const Screen = "ECMAScript 6"
// 输出false
console.log(Screen === window.Screen)
因此,如果不想为全局对象window创建属性,或者为了避免覆盖window对象的属性,则应该使用let和const来声明变量