变量声明var、let和const

157 阅读3分钟

1.var关键字

作用域:var定义的变量会成为包含它的函数的局部变量,不过定义变量时省略var操作符,创建的变量会变成全局变量可以在函数外部访问到。

function test(){ var a = 'a'; b = 'b'; }
test();
console.log(a);//报错 
console.log(b);//'b'

var声明变量时会自动提升导函数作用域顶部

function test(){ console.log(a); var a = 'a'; } 
test();//undefined

image.png

等价于

function test(){
    var a; 
    console.log(a); 
    a='a'; 
} 
test();

var允许多次声明同一个变量。

2.let声明

作用域:块作用域。

image.png

因为let声明的变量作用域仅限于该块内部,所以变量b不能在if块外被引用。 let不允许同一个作用域下出现冗余声明,会导致报错。

image.png

js引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标识符不会报错,而这是因为同一个块中没有重复声明。

image.png

对声明冗余不会因为混用let和var而受影响。这两个关键字并不是声明不同类型的变量,它们只是指出变量在相关作用域如何存在。

暂时性死区

let和var存在的另一个重要的区别是let不会提升变量。

在解析代码是js引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量,在let声明之前的执行瞬间被称为“暂时性死区”,在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

console.log(aa)//undefined
var aa = 'aa'
console.log(bb)//报错,bb没有定义
let bb = 'bb'

全局声明

与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性。(var声明的变量则会成为window对象的属性),不过let声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内延续,因此必须避免页面重复声明同一个变量。

var aa = 'aa'
console.log(window.aa)//'aa'
let bb = 'bb'
console.log(window.bb)//undefined

条件声明

在使用var声明变量时,由于变量声明会被提升,js引擎会自动将多余的声明在作用域顶部合并为一个声明。但是let的作用域是块,所以不可能检查之前有没有使用let声明过同名变量,同时也就不可能在没有声明的声明它。使用try/catch语句或typeof操作符也不能解决,因为条件块中let声明的作用域仅限于该块。

<script> 
    var name = 'nicholas'; 
    let age = 26; 
</script> 
<script> 
    var name = 'mark';//这里没问题,可以被作为提示变量处理,不需要检查之前是否有同名变量 
    let age = 26;//age之前生命过这里会报错 
</script>

for循环

使用var声明的for循环的迭代变量会渗透到循环体外部。let会使迭代变量的作用域仅限于for循环内部。

  for(var i=0;i<5;i++){

  }
  console.log(i);//5
  for(let i=0;i<5;i++){

  }
  console.log(i);//报错i没有定义

let还可以用于对迭代变量的奇特声明和修改,比如下面的代码

  for(var i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},0)
  }//你可能以为会输出0,1,2,3,4。实际输出5,5,5,5,5

之所以是这样,是因为在退出循环时保存的迭代变量是5,在执行之后的setTimeout时,所有的i都是同一个变量,所以输出的都是同一个值,而用let声明变量时,js引擎会为每个迭代循环声明一个新的迭代变量,所以setTimeout引用的是循环过程中的每个迭代变量的值。

  for(let i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},0)
  }//0,1,2,3,4

3.const声明

const的行为与let基本相同,但是const声明变量时必须同时初始化变量,且修改const声明的变量会导致报错。const也不允许重复命名。 作用域:块作用域。

image.png

const声明的限制只适用于它指向的变量的引用。如果const引用的是一个对象,修改对象内部的属性不会报错。

image.png

cosnt不能和let一样用来声明迭代变量,因为迭代变量会自增。但是const可以用来声明不会被修改的for循环变量,如for-of和for-in

 const obj = {a:'a',b:'b'}
 const arr = [1,2,3,4,5]
  for(const key in obj){
    console.log(key);
  }//a,b
  for(const key in arr){
    console.log(key);
  }//1,2,3,4,5