let(声明局部变量)
let特点是什么?
作用域为 块级作用域、无变量提升、同一作用域内不可以重复声明
和var的区别?
var 作用域为 函数作用域、有变量提升、可以重复声明、有暂时性死区
关于作用域
作用域:JS(ES6之前)作用域有 全局作用域 、函数作用域(局部作用域)。
ES6新增块级作用域。
-
全局作用域:
最外层函数和在最外层函数外面定义的变量拥有全局作用域。
所有末定义直接赋值的变量自动声明为拥有全局作用域(不论函数内外)。在全局作用域中创建的变量和函数都被作为window对象的属性。
全局作用域在页面打开时创建,页面关闭时销毁。
全局变量在全局(代码的任何位置)下都可以使用;全局作用域中无法访问到局部作用域中的变量。
-
函数作用域(局部作用域):函数内部为局部作用域。
调用函数时创建函数作用域,函数执行完毕之后,函数作用域销毁;
每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的。
var num = 10; // 全局作用域内
function nu(){
var num = 20; //函数作用域内
console.log(num); //20
}
nu();
console.log(num); //10
- 块级作用域:{} 的内部即为块级作用域,if语句和for语句里面的{}也属于块作用域。
function nu() {
{
var a = 10;
let b = 20;
console.log(a); //10
console.log(b); //20
}
console.log(a) //10,var并不能将变量的适用范围限制在块级作用域内
console.log(b) // b is not defined,let可以将变量范围限制在块级作用域内
}
nu();
console.log(a); // not defined
console.log(b) // not defined
如果没有块级作用域,可能会:
(1)变量提升导致内层变量可能会覆盖外层变量
var i = 5;
function func() {
console.log(i);
if (true) {
var i = 6;
}
}
func(); // undefined
详细解释(2021-3-4):
疑问:是先执行console.log还是先变量提升,如果先执行console.log那么执行到true的时候,再变量提升将var i提升到console之前但此时console已经执行完毕了啊;如果先变量提升那么不是先执行true再console吗,这不符合js的从上往下执行。
解释:因为没有块级作用域,所以var i =6和console其实是在一个作用域里面的,所以理所应当地直接变量提升,var i;提升到console之前。
(2) 用来计数的循环变量泄露为全局变量
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log(i); // 10
var a = [];
for (var i = 0; i < 3; i++) {
a[i] = function () {
console.log(i); //3个3
};
}
详细解释(2021-3-4)
由于var有变量提升机制,所以var会只声明一次,然后在每次地作用域中改变i 的值;
而let没有变量提升机制,所以每次循环都会执行一次,声明一个新变量(但初始化的值不一样),又因为let声明的变量是在各自的块级作用域中,所以不存在重复声明的情况,即
{let i = 0}
{let i = 1}
…
为什么会是三个3?
{
//我是父作用域
var i = 0;
if (0 < 3) {
a[0] = function () {
//我是子作用域
console.log(i);
};
};
i++; //为1
if (1 < 3) {
a[1] = function () {
console.log(i);
};
};
i++; //为2
if (2 < 3) {
a[2] = function () {
console.log(i);
};
};
i++; //为3
// 跳出循环
}
//调用N次指向都是最终的3
a[0](); //3
a[1](); //3
a[2](); //3
- 为什么let不会?
因为let在每一次循环中都在其作用域中新声明了一个。 - 为什么会记得上一个i是多少并在此基础上自增?
从阮一峰ES6入门获取到知识:JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
借鉴:for循环中let与var的区别,块级作用域如何产生与迭代中变量i如何记忆上一步的猜想
块级作用域的一般使用:
(1)for 循环和 let 配合使用
for (let i = 0; i < 10; i++) {
console.log(i);
}
console.log(i); // i is not defined
const(声明一个只读的常量)
一旦声明,常量的值就不能改变,并且需要立即初始化。
function func(){
const PI;//未立即赋值导致报错,Missing initializer in const declaration
PI = 3.14;
console.log(PI);
};
func();
常见面试题
- var、let、const的区别
let、const 有块级作用域,var没有块级作用域
let、const 没有变量提升,var有变量提升
let、const 不可以重复声明,var可以
let、var可以先声明再赋值,const声明同时必须赋值
let、var声明赋值后变量值还可以修改,const声明的是常量,不可以修改
推荐文章: JS 全局作用域和局部作用域.