1.Var声明以及变量提升(Hosting)机制
在函数作用域或者全局作用域中通过关键字var声明的变量,无论在哪声明的,都会被当成在当前作用域顶部声明的变量,这就是我们常说的变量提升机制(Hosting),下面以一个函数来说明:
function getValue(condition){
if(condition){
var value = "blue"
//其他代码
return value
} else {
//这里可以设置访问变量value,其值为undefined
return null
}
//这里可以访问变量value,其值为undefined
}
复制代码
如果你不熟悉JS的话。可能你会认为只有当condition的值为true时,才会创建变量。但是事实上无论如何变量value都会被创建。在编译阶段JavaScript引擎会将上面的getValue函数修改成下面这样的:
function getValue(condition){
var value
if(condition){
value = "blue"
//其他代码
return value
} else {
return null
}
}
复制代码
变量value的声明被提升至函数的顶部,而初始化操作依旧留在原处执行,这就意味着在else子句中也能访问到这个变量,而且因为此时变量还没有初始化所以他的值是undefined。为此ES6引入了块级作用域来强化对变量声明周期的控制。
2.块级声明
块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域存在于:
- 函数内部
- 块中(字符{和}之间的作用域)
let声明
let声明的语法和var相同 ,但是用let来声明就可以把变量的作用域限制在当前代码块中,由于let不会变量提升,所以开发的时候我们通常把let语句放到封闭代码块的顶部,以便整个代码块都可以访问。
function getValue(condition){
if(condition){
let value = "blue"
//其他代码
return value
} else {
//变量value,在这里不存在
return null
}
//变量value,在这里不存在
}
复制代码
变量value改用let进行声明后,不再被提升至函数顶部。执行流离开if块,value立即被销毁,如果condition的值为false,就永远不会声明并且初始化value。
禁止重复声明
如果作用域中已经存在某个标识符,这个时候再用let声明他就会报错。
const声明
1)使用const声明的是常量,他的值一旦设定之后不能修改。2)因此每个const声明的常量必须初始化,示例如下:
const maxItem = 30
cosnt name //语法错误,常量没有初始化
复制代码
const 与 let
他们两个的声明都是块级标识符,所以常量也只在当前代码块内有效,一旦执行到块外立即会被销毁。同样常量也不会提升至作用域顶部。
用const声明对象
要记住,const声明不允许修改绑定,但是允许修改值。这也就是意味着用const声明对象之后,可以修改该对象的属性值:举个例子:
const person = {
name : "laodai"
}
//可以修改对象的属性值
person.name = "xiaodai"
//抛出语法错误
person = {
name : "xiaodai"
}
复制代码
上面这段代码中,绑定的person的值是一个包含一个属性的对象,改变person.name的值不会抛出任何错误,因为修改的是person包含的值,但是直接给person赋值,也就是要改变他的绑定,就会抛出错误。
3.临时死区
与 var 不同 let 和 const 声明的变量不会被提升到作用域的顶部,如果在少女革命之前访问这些变量,可能会触发引用错误,看一下下面这段代码:
if(condition){
console.log(typeof.value) //引用错误
//到变量赋值之前的区域都是临时死区
let value = "blue"
}
复制代码
由于 console.log(typeof.value)语句会抛出错误,所以用let定义并且初始化变量value的语句不会执行。这个时候的value还处于JavaScript社区所谓的临时死区中。
JavaScript引擎在扫描代码的时候发现声明变量的时候,要么就把他提升到作用域顶部(var)要不然就放到临时死区中。访问临时死区中的变量会触发运行时的错误。只有执行过变量声明过的语句后,变量才会从临时死区中移除出,正常访问。