小技巧:var 和 let 的隐藏区别

686 阅读2分钟
var存在变量提升,而let没有
console.log(window.name) //undefined
console.log(window.age) // SyntaxError


var name = 'tom'
let age = 12

上面的代码,被js引擎修改为

var name 

console.log(window.name) //undefined
console.log(window.age) // SyntaxError

name = 'tom'
let age = 12

var声明的全局变量会成为window的属性而let则不会

使用var声明的全局变量会成为window对象的属性,而let则不会

var name = 'tom'
let age = 12

console.log(window.name) //tom
console.log(window.age) //undefined

但是,上面的age变量仍在全局范围内可以使用

为何var可以重复声明同一个变量,而let不可以?

我们都知道,使用var可以反复声明同一个变量,例如


function foo() {
    var name = 'tom'
    var name = 'tom'
    var name = 'tom'
    console.log(name) //tom
}


而使用let则不可以,会报错


function foo() {
    let name = 'tom'
    let name = 'tom'
    let name = 'tom'
    console.log(name) //Syntaxerror 因为name已经声明过
}


你可能会说,ES6中规定let不能重复声明,但是为什么呢?

其实这和var与js引擎本身有关

我们都知道,var声明的变量存在着作用域提升

function bar() {
    console.log(age)
    var age = 12
}

bar() //undefined

之所以不会报错,是因为js引擎执行了以下操作

function bar() {

    var age
    console.log(age)
     age = 12
}

bar() //undefined

这就是所谓的作用域提升(hoist),把所有使用var声明的变量都提升到函数作用域的顶部

可这和var能重复声明有什么关系呢?

这就不得不说js引擎干的另外一件事,它会自动合并作用域顶部的重复声明

function foo() {
    ...
    var name = 'tom'
    var name = 'tom'
    var name = 'tom'
    ...
    console.log(name) //tom
}

也就是说,像上面这样的重复声明,声明的变量name会被提升到作用有的最顶部

然后js引擎会检测是否存在重复申明的变量,并将多余的声明删除

会被合并成下面这样

function foo() {
    var name = 'tom'
    ...
    console.log(name) //tom
}

而由于,let声明的变量作用域就是当前代码块,不能被提升,所以js引擎无法检测到是使用let否声明过同名的变量

从而也就无法合并同名变量

进而导致重复使用let声明重名变量报错

而且,重复声明和使用var与let的方式无关

var name 
let name //SyntaxError

let age
var age //SyntaxError