.
众所周知,var 和 let 最大的区别是作用域:var 的函数声明作用于函数作用域、全局声明作用于全局作用域,而let 的声明范围是块级作用域。
(对于作用域的详解可参考我的另一篇博客:【JS全局、函数、块级作用域】)
为什么会有这样的区别呢?
1、var 和 let 的函数声明
我们都知道,变量的整个过程是:声明 => 初始化 => 赋值。
var 具有声明提升的特点,会将变量的声明提升至函数顶部,并且会将变量初始化为undefined,但对于变量的赋值是无法提升的。
因此下面的代码会输出undefined:
function top() {
console.log(test) //输出undefined
var test = "测试"
console.log(test) //输出“测试”
}
根据 var 的提升规则,这个函数实际等价于:
function top() {
var test //声明提升,且test被初始化为undefined
console.log(test) //输出undefined
test = "测试" //赋值未提升
console.log(test) //输出“测试”
}
因此 var 不管声明在函数的哪个区域,其实都是声明在了函数的顶部,所以整个函数都能访问到该变量,故 var 是的函数声明是作用于函数作用域的。
但 let 并没有声明提升的特点,因此let 只作用于声明之后的块级区域。若在为 let 声明之前就使用该变量,即使在同一块级区域也会报错,这是因为造成了暂时性死区,而造成 let 暂时性死区的原因也恰恰是因为 let 没有声明提升。
.
2、 var 与 let 全局声明的区别
var 的全局变量是作用在全局作用域上的,而 let 的声明是块级的,想一想,但如果在全局作用域去声明 let 变量的话,是不是 let 声明的变量就和 var 一样作用在全局作用域了呢?
其实不是的,因为 var 声明的全局变量是会添加至 window属性上的,而 let 和 const 声明的变量并不会。所以在这种情况下虽然在“全局”确实可以使用 let 变量,但我们也不能说此时 let 的声明是全局作用域,而是伪全局作用域。
换而言之,var 声明的全局变量作用范围是整个 window,而 let 声明的全局变量作用范围只是整个文件。
也正因为 var 声明的全局变量会成为 window 的属性,所以在声明提升时,如果是在函数作用域声明的 var 变量,则会将声明提升至函数顶部,如果是在全局作用域声明的 var 变量,则会将声明提升至window。
如以下代码,只有 var 声明的全局变量 name1
成为了 window 的属性,其他文件都可以通过 window.name1
拿到该变量,而 let 声明的全局变量 name2
和 var 声明的函数变量 name3
都不是 window 的属性。
.
3、var 与 let 的冗余声明
除了作用域的区别,var 和 let 还有很大一个区别便是是否允许重复声明,var 是允许重复声明的,而 let 是不允许同一个块作用域中出现冗余声明的。
但是要明白,此处说的不允许冗余声明,指的并不是声明类型,而是变量本身不允许重复声明。
即以下这种情况也会报错:
let age = 9;
var age = 10; //不允许重复声明