目录
1. let =》if 和 for while 内部 具备块级作用域
先来一个表格
var | let | const | |
是否存在块级作用域 | 不存在 | 存在 | 存在 |
是否存在变量提升 | 存在 | 不存在 | 不存在 |
是否存在暂时性死区 | 不存在 | 存在 | 存在 |
是否可以重复声明 | 可以 | 不可以 | 不可以 |
是否可以修改值【不同于重复声明】 | 可以 | 可以 | 不可以 |
注意点 | let 必须先声明 再赋值 |
|
let的特点
1. let =》if 和 for while 内部 具备块级作用域
for(var j = 0; j < 5; j++) {
}
console.log(j); // 5 这里的5可以访问到 不具备块级作用域 存在内存泄露的风险
for(let i = 0; i < 5; i++) {
}
console.log(i); // 报错 未定义 =》for里面是块级作用域 =》 防止循环的变量i 变成全局变量
if(5 > 3) {
let b = 3
console.log(b); // 这里能够正常输出 3
}
console.log(b); // 报错 未定义
如果没有块级作用域,不声明就使用变量 是很不好的编码习惯
2. let 必须先声明 再使用 =》不存在变量提升
console.log(i)
var i // undefined
console.log(j);
let j; // 报错 没有变量提升 必须先声明 再使用
能够解决变量覆盖的问题
// 观察如下代码 c输出是什么?
var c = 3
function fn2() {
console.log(c) // undefined
if(true) {
var c = 4
}
}
fn2()
// 上面代码相当于下面,里面的if语句的var声明会提升到function最前面
var c = 3
function fn2() {
var c
console.log(c) // undefined
if(true) {
c = 4
}
}
fn2();
// 但是下面用let 并不存在变量提升因此if语句里面的d的let = 4声明不会覆盖let d = 3
let d = 3
function fn3() {
console.log(d) // 3
if(true) {
let d = 4
}
}
fn3()
3. 暂时性死区1
暂时性死区里,不管外面是否有全局变量。块级作用域内和外部断绝关系,内部没有先声明再使用变量就会报错
// 使用let 产生暂时性死区
// 块级作用域里面 不能访问外部的变量
// 不能在声明前使用变量 因此即使if外面有b变量 里面的console =》 b 也会报错
let b = 3
if(true) {
console.log(b);
let b = 4
}
4. 暂时性死区2
函数的形参也存在暂时性死区
let b = 3
function fn (a = b, b = 2) {
}
console.log('看这里');
fn() // 这里会报错 即便函数外部已经声明了b
// 上面代码报错的原因是 a = b 是让b赋值给a,但是此时b还没有赋值,=》函数的形参也会产生暂时 性死区 =》不能使用未声明的变量 =》
// 如果反一下 先声明b 再把b赋值给a
// function fn (b = 2 ,a = b ) {
// console.log(1);
// }
// fn()
5. 题目1
1. arr[0] 和 arr[1] 都是函数 两个函数执行输出的都是2 为什么?
2. 两个函数里面打印i,关键是d此时的i变量去哪里找?
3. 去函数外面上一级找,为什么?因为函数里面并没有声明i =>根据作用域链 往上一级查找的原则
4. 上一级的i是函数外面的i,是全局变量i =>此时全局变量i是2,为什么?
5. 因为var声明的变量不存在块级作用域,for循环结束外面输出的i就是2,因此两个函数输出都是2
var arr = []
for(var i = 0; i < 2; i++) {
arr[i] = function() {
console.log(i);
}
}
arr[0]() // 2
arr[1]() // 2
如下图
var arr2 = []
for(let j = 0; j < 2; j++) {
arr[j] = function() {
console.log(j);
}
}
// // console.log(j); 这里打印j会报错 => j不是全局变量 =>
// arr[0]() // 0
// arr[1]() // 1
// // 1. 两个for循环 因为let的存在 会生成两个块级作用域
// // 2. 因此j会去各自的块级作用域里面[=>作用域链 向上一级]查找j
// // 3. 因此输出的是0 和 1
// // 4. 此时函数输出的分别是0 和 1
如下图
6. 能够重复声明?能否修改?
let m = 3
m = 4
console.log(m); // 4 可以修改
let n = 5
// let n = 6 // 再次修改就会报错
console.log(n);
不能够重复声明。也就是使用了一次 let m = 3; 再次使用let m = 4就会报错
可以修改。也就是 let n = 3;再写 n = 4 这样是ok的
const的特点
1.基本:
建议:
1. 常量 不能 只声明不赋值
2. 常量名 最好都大写
3. 固定不变的值用常量 =》 变量的值会时时刻刻被js检测 =》常量不会 能够提高js性能
const PI = Math.PI
console.log(PI);
// const A // 报错
2. 具备块级作用域 if for 外部不能访问
if(true) {
const PI2 = 3.141592653589793
console.log(PI2);
}
// console.log(PI2); // 报错
3.声明后能否修改?
总结:
简单数据类型声明后不能修改
复杂数据类型内部可以修改,外部直接赋值会报错,因此不能整体修改。
const赋值是存地址,而不是值。直接赋值修改就是修改整体的地址
// 修改
// 简单数据类型不能修改
const AB = 123
// AB = 345 报错
// 复杂数据类型 不能直接整体赋值 但是可以改内部
const ARR = [1,2,3]
console.log(ARR);
// ARR = [] // 报错
ARR[0] = 3
console.log(ARR); // [3,2,3]
const OBJ = {
name: '123'
}
OBJ.name = '456'
// OBJ = {} // 报错
// console.log(OBJ);
4. const也有暂时性死区
function fn4() {
const ABC = 123
if(true) {
console.log(ABC);
const ABC = 345
}
}
fn4() // 报错 里面的console 无法访问if外面的const声明
5. 不存在变量提升
const ABC = 123
function fn4() {
console.log(ABC); // 123
if(true) {
const ABC = 345
}
}
fn4()
最后总结一下:
-
let 和 const 都拥有块级作用域。 什么是块级作用域 =》 if 和 for 在花括号里面的变量外面是访问不到的。但是var声明的变量是可以的,var存在不规范之处
-
let有暂时性死区 =》在块级作用域里面,如果一个变量没有声明,是不能去访问全局变量的。函数的形参也有暂时性死区,a = b; b = 2是错的
-
let必须先声明 再赋值 ; var有变量提升,可以先赋值再声明
-
const声明的变量名要求建议大写。
-
const声明变量 ,声明和赋值要同时进行,不能只进行一个
-
const声明的变量是引用传递,简单数据类型声明后不能修改,是常量;复杂数据类型比如数组可以改数组里面的值,但是不能够整体数组重新赋值。
结尾:
学习id: 201903090124
现在是大三学生,学习到了vue阶段【vue框架真的好难好难呜呜】,如有不对的地方,欢迎指正,一起努力呀。如有转载请注明出处