变量声明
在JavaScript中声明变量有三个关键字
var是最原始的,那就不必多说了,现在主要说的是let和const这两个关键字来声明变量和var有何不同
let
应用:在业务逻辑很复杂的时候,可以防止内层变量覆盖外层变量
eg1.
if (true) {
let a = 3;
console.log(a); //3
}
console.log(a); //a is not defined
可以看到在if语句里面可以访问a变量
但是在if语句的外面是访问不了的.
特点1
用let声明的变量只在当前作用域中生效
eg2.
if (true) {
let b = 4;
if (true) {
let c = 6;
console.log(b) //4
}
console.log(b); //4
console.log(c); //c is not defined
}
if (true) {
var b = 4;
let a = 2;
}
console.log(b); //4
console.log(a); //a is not defined
这个例子可以看出:在一个大括号中,使用let声明的变量才具有块级作用域,var关键字是不具有的
使用块级作用域还有一个好处
可以防止循环变量变成全局变量
eg3.
for (var i = 0; i < 4; i++) {
console.log(i); //0 1 2 3
}
console.log(i); //4
在循环体的外面还是可以访问到变量i,如果这个for循环存在于全局作用域中,那我的变量 i 就变成了全局作用域;循环结束, i 变量就没有必要了,
所以可以使用let来声明变量
eg4.
for (let i = 0; i < 4; i++) {
console.log(i); //0 1 2 3
}
console.log(i); // i is not defined
这样就可以防止 i 变量变成全局变量了;
特点2
使用let来声明的变量不存在变量提升
eg5.
console.log(a);
let a = 4; //报错
特点3
使用let来声明的变量具有暂时性死区
也就是说 在块级作用域内使用let关键字声明的变量会被整体绑定在块级区域,不再受外部影响;
eg6.
var a = 3;
if (true) {
console.log(a); //报错
let a = 4;
}
不会再向上级作用域查找变量a;
因为在块级作用域中用 let 声明了变量 a ,那么变量 a 就跟这个块级作用域绑定在一起,不受外界影响.所以在声明之前直接输出 a 变量会报错.因此,在该作用域内使用 let 声明的变量,跟外面的同名变量是没有关系.
思考题
1.
var arr = [];
for (var i = 0; i < 4; i++) {
arr[i] = function() {
console.log(i);
}
}
arr[0](); // ?
arr[1](); // ?
答案: 4 4
解析: for循环处于全局作用域中,在里面用var创建了一个变量 i , 变量 i 就是全局变量,函数执行时,for循环早就已经循环结束,此时 i 的值已经是4了,所以函数输出的值是4.由于数组中存了两个函数,在执行时输出的都是全局变量 i ,所以两次输出都是4,关键点在于变量 i 是全局的,函数执行时输出的都是全局作用域下的 i 值
2.
let arr = [];
for (let i = 0; i < 4; i++) {
arr[i] = function() {
console.log(i);
}
}
arr[0](); // ?
arr[1](); // ?
答案: 0 1
解析:由于使用let关键字声明的变量具有块级作用域.在for循环结束后,产生了两个块级作用域,产生的两个块级作用域中都用自己的变量 i 互不影响,数组中存储的两个函数在执行时,要分别在自己的块级作用域中查找变量 i ,第一个函数执行时,输出的是第一个块级作用域中的 i 值 ,就是0; 第二个函数输出的第二个块级作用域中的 i 就是 1; 关键点 :每一次循环都产生一个块级作用域,每个块级作用域里面的变量都是不同的.
const
作用: 声明常量,常量就是值(内存地址) 不能变化的量
特点1:具有块级作用域
eg7.
if (true) {
const a = 3;
}
console.log(a); //a is not defined
所以在 if 语句里面用const声明的常量a,在外面是访问不到 a 变量的
eg8.
if (true) {
const a = 3;
if (true) {
const a = 5;
console.log(a); //5
}
console.log(a); //3
}
console.log(a); //a is not defined
每个块级作用域中的同名变量互不影响
特点2: 使用const关键字声明的变量必须赋值,否则会报错
eg9.
const a //报错 .Missing intializer in const declaration
意思是,丢失了初始值;
所以用const声明的常量一定要赋初始值
特点3 使用const声明的常量,值不能修改
分两种情况.
1,基本数据类型
一旦赋值,值不可更改,(比如数值或者字符串类型的值)
eg10.
const a =3;
a=5;
报错// Assignemt to constant variable
2,复杂数据类型
不能重新赋值,但是可以更改数据结构内部的值(比如数组,或者对象)
eg10.
const arr = [1, 3];
arr[0] = 2;
arr[1] = 4;
console.log(arr); // 2 4
因为只更改了arr数组内部的值,并没有改变存储的地址
arr = [5, 6] 报错 //Assignment to constant variable
这里arr变成了一个新数组,地址都不一样的了,所以会报错
所以说对于赋值数据类型来说,内部的值可以更改,但是重新赋值就是不行.
也就是说常量值对应的内存地址不可更改
总结
let const var 的区别
1. 使用 var 声明的变量,作用域为该语句所在的函数内,存在变量提升
2. 使用 let 声明的变量,作用域为该语句所在的代码块内,不存在变量提升
3. 使用const声明的是常量, 在后面出现的代码中不可更改该常量的值.不存在变量提升
var | let | const |
---|---|---|
函数作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可以改 | 值可以改 | 值不可以改 |