每一个js程序执行的时候会分为编译阶段和执行阶段(赋值语句是属于执行阶段):编译阶段就是把js变量的声明提升到当前作用域的最前端,就会生成一个scope域,把所有声明的的变量放入scope。当执行代码时,就会到scope里寻找所需要的变量。var声明变量会变量提升到作用域的最前端生成var 变量=undefined。
来:我们一起看看下图表结论
| 关键字 | 变量提升 | 块级作用域 | 重复声明同名变量 | 重新赋值 |
|---|---|---|---|---|
| var | ✔ | ❌ | ✔ | ✔ |
| let | ❌ | ✔ | ❌ | ✔ |
变量提升:
变量提升:
/*用var声明变量*/
console.log(num); //输出undefined
var num=10;
//上面代码运行时相当于下面的写法
/************************************/
//编译过程变量提升后的代码
var num=undefined //声明到作用域顶端
//执行过程代码
num=10
consosole.log(num) //输出undefined
/*用let声明变量*/
console.log(b); //报错 b is not defined
console.log(num1); //报错 Cannot access 'num1' before initialization初始化前无法访问
let num1=10;
/*
从let声明变量来看,let是存在变量提升的,但是不能被初始化。如果没有,那我们的log(x)的报错是与log(num1)的报错是一样的,但是var的变量提升的空间对象与let的空间对象并不并存在一起,let放在临时暂死区。 那什么叫临时暂时区,let声明的变量提升是存在的,但是不让用。变量提升其实是一个bug,let的产生就是用来修补变量提升bug的方案,变量提升是js的运行机制。
块级作用域:ps:一对{}就是一个块级作用域
{
var a=‘hello'
}
cosole.log(a); //能正确输出hello
for(var i=0;i<5;i++){
}console.log(i)//输出5
let a='hello'
}
cosole.log(a)//ReferenceError: a is not defined
for(let i=0;i<5;i++){
}console.log(i)//ReferenceError: i is not defined
var是不存在块级作用域的,let是存在块级作用域的
重复声明同名变量:
//var可以声明同名变量,实际第二次声明是对第一次声明的重新赋值
var a=10;
var a=100;
console.log(a);//100
//let不能重复声明同名变量,即使之前使用var也会报错
let a=10;
let a=100;
console.log(a)//Identifier 'a' has already been declared
var a=10;
let a=20;
console.log(a);//SyntaxError: Identifier 'a' has already been declared
//var和let的作用域不一样是可以同时声明
var a=10;
{
let a=100;
}
console.log(a);//10
重新赋值:
//let 声明变量可以重新赋值,var也可以
let a=10;
a=20;
console.log(a)//20