javascript进阶学习:var、let、const变量声明区别,变量提升,临时死区

蛰伏已久 蛰伏已久 2019-01-23

var及变量提升

在ES6之前我们都是通过var声明变量,而通过var声明变量存在变量提升的问题

在函数作用域或全局作用域中通过var关键字声明的变量,无论实际上是在哪里声明的,都会被当做在当前作用域顶部声明的变量,这就是变量提升机制

看看下面的例子,分别打印出什么

function test() {
    console.log(value)   
}
test()           //undefined
var value="123"
test()           //123

在声明变量value之前,就调用了函数test,并没有报错(value未定义),而是打印出了undefined。在预编译阶段,javascript引擎将上面的代码修改成下面这样

var value
function test() {
    console.log(value)
}
test()
value="123"
test()

再看一个例子

function test(condition) {
    if(condition){
        var value="123"
        console.log(value)
    }else {
        console.log(value)
    }
}

test(false)    //undefined

condition为false,进入了test函数的else分支,此时并没有定义value,但是打印出来仍然是undefined,而不是报错,在预编译阶段,javascript引擎将上面的代码修改成下面这样,这样看起来就很好理解了

function test(condition) {
    var value
    if(condition){
        value="123"
        console.log(value)
    }else {
        console.log(value)
    }
}

test(false)

再看一个例子

function test() {
    console.log(value)     //undefined
    var value="456"
    console.log(value)     //456
}

var value="123"
test()

按理说第一次打印的应该是全局变量value,即“123”,第二次打印的是局部变量value,即“456”,而实际第一次打印的是undefined,这也是由于变量提升导致的,在预编译阶段,javascript引擎将上面的代码修改成下面这样,这样就很容易理解了

function test() {
    var value
    console.log(value)
    value="456"
    console.log(value)
}

var value="123"
test()

再来看一个经典例子,在循环条件中声明的变量i,在循环体外面,仍然可以访问

for(var i=0;i<10;i++){}
console.log(i)   //10

let声明

let声明的变量不会被提升,let声明的变量在其所在作用域外无法访问

for(let i=0;i<10;i++){}
console.log(i)   //报错 i is not defined

块级声明用于声明在指定块的作用域之外无法访问的变量,块级作用域(词法作用域)存在于:

  • 函数内部

  • 块中(级{}之间的区域)

如下,通过let声明的value,只在当前块中有效,其他地方使用均报错

function test(condition) {
    if(condition){
        let value="123"
    }else {
        console.log(value)  // value is not defined
    }
    console.log(value)     // value is not defined
}

test(true)   
test(false)

如果作用域中已经存在某个变量,let禁止重复声明

var value="123"
var value="456"   //允许
let value="456"   //报错 Identifier 'value' has already been declared

const声明

const用于声明常量,其值一旦声明不能更改

const value=123
value=456   //报错 Assignment to constant variable.

而如果const声明的是一个对象,则可以更改对象的属性,但是不能更改对象的引用。可以理解为常量存储的是对象的引用地址,只要引用地址不变即可,内容随便变

const obj={

}
obj.a=123   //允许
obj={}      //报错

const和let一样,不存在变量提升问题

临时死区

与var不同,let和const声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,即使是相对安全的typeof操作,也会触发错误

if(true){
    console.log(typeof value)    //报错
    let value=123
}

在块内部,如在let声明前就使用某个变量,会引发错误,就好像这部分是一个死区一样

分享到

点赞(0)