js中的let和var区别

摘抄自https://blog.csdn.net/qq_38290251/article/details/107576414

目录

1、var有变量提升,let 没有变量提升

2、var 可以重复声明,而let不能重复声明

3、let可以定义块级作用域 { }

4、临时失效区 (暂时性死区)

① 什么是暂时性死区?

② 表现在哪里?

5、let 配合for循环的独特应用

① 用 var 配合 for 循环,有导致什么问题?

② let非常适合用于 for循环内部的块级作用域

6、拓展

① 为什么ES6规定暂时性死区和 let 、const 语句不出现变量提升?

② 为什么ES6中需要块级作用域?

1、var 有变量提升,let 没有变量提升
变量提升 :将变量提升到当前作用域的上边

console.log(a) // 定义了没有赋值,值为 undefined
var a = 10
console.log(b) // 报错 Uncaught ReferenceError: b is not defined。
let b = 10

var a = 99
f()
console.log(a)
function f() {
console.log(a)
var a = 10
console.log(a)
}
输出结果:undefined 10 99

(注意:这里是先触发 f 函数:变量 a 在函数内进行了提升,所以打印的时候是 undefined)

2、var 可以重复声明,而let不能重复声明
var可以重复声明

var c = 10
var c = 20
console.log(c) // 20
let不允许在相同作用域内,重复声明同一个变量。

否则报错:Uncaught SyntaxError: Identifier 'XXX' has already been declared

let c = 10
let c = 20
console.log(c) // 报错
// 报错
function func() {
let a = 10;
var a = 1;
}

// 报错
function func() {
let a = 10;
let a = 1;
}
function func(arg) {
let arg;
}
func() // 报错


function func(arg) {
{
let arg;
}
}
func() // 不报错
3、let可以定义块级作用域 { }
var 是全局声明;

var m = 5
if (m) {
var n = 100
}
console.log(n) // 100
let 可以定义块级作用域变量,是局部变量,只在它当前的代码块内有效,而且有暂时性死区的约束。

var m = 5
if (m) {
let n = 100
}
console.log(n) // 报错
下面的函数有两个代码块,都声明了变量 n,运行后输出 5。

这表示外层代码块不受内层代码块的影响。

如果两次都使用var定义变量n,最后输出的值才是 10。

function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
4、临时失效区 (暂时性死区)
① 什么是暂时性死区?
ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错

使用 let 或 const 声明的变量,会针对这个变量形成一个封闭的块级作用域,在这个块级作用域当中,如果在声明变量前访问该变量,就会报 referenceError 错误;如果在声明变量后访问,则可以正常获取变量值: ​​​​​​​

总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区” (当前作用域不允许同名的变量进来)

function foo() {
let bar = 3
console.log(bar)
}
foo()
这段代码正常输出 3。因此在相应花括号形成的作用域中,存在一个“死区”,起始于函数开头,终止于相关变量声明的一行。在这个范围内无法访问 let 或 const 声明的变量。

② 表现在哪里?
用 let 声明的变量,不存在变量提升。而且要求必须 等 let 声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误。

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

var x = 10
function a() {
console.log(x)
let x = 20
// console.log(x);
}
a()


var x = 10
function a() {
// console.log(x)
let x = 20
console.log(x); // 20
}
a()
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError

let tmp; // TDZ结束
console.log(tmp); // undefined

tmp = 123;
console.log(tmp); // 123
}
5、let 配合for循环的独特应用
① 用 var 配合 for 循环,有导致什么问题?
var配合for循环,此时输出了10个10。

下面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。

每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。

也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10

for (var i = 0; i < 10; i++) {
setTimeout(function () { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
同步注册回调函数到异步的宏任务队列,当执行到打印的时候,同步代码for循环已经执行完成。

② let非常适合用于 for循环内部的块级作用域
JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域。

用 let 声明的变量传入到 for 循环体的作用域后,不会发生改变,不受外界的影响。

for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
let配合for循环,使用输出0 1 2 3 4 5 6 7 8 9

i 虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。

6、拓展
① 为什么ES6规定暂时性死区和 let 、const 语句不出现变量提升?
主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。

② 为什么ES6中需要块级作用域?
ES5只有全局作用域和函数作用域,没有块级作用域,这带来了很多不合理的场景。

01、内层变量可能会被覆盖外层变量

var tmp = new Date();

function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}

f(); // undefined
上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。

但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

02、用来记数的循环变量泄露为全局变量

下面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

var s = 'hello';

for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}

console.log(i); // 5
块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。

// IIFE 写法
(function () {
var tmp = ...;
...
}());

// 块级作用域写法
{
let tmp = ...;
...
}
ES6 入门教程

7、总结
① let 和 var 的区别
var 存在变量声明提升;let 不存在变量声明提升。

在相同作用域内,var 可以重复声明;let 不允许重复声明同一个变量。

var 是全局声明;let 可以定义块级作用域,是局部变量,只在当前代码块内有效,而且有暂时性死区的约束。

② 暂时性死区
如果在某个作用域中存在 let 和 const 命令,这个作用域从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。

这在语法上,称为“暂时性死区” (当前作用域不允许同名的变量进来)

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

③ let 配合 for 循环 和 var 配合 for 循环有什么区别?
var 配合 for 循环,var 会声明一个全局变量 i,每次循环都是在改变同一个变量 i,会导致异步输出的结果都是同一个值;还会导致循环变量泄露为全局变量。

而 let 配合 for 循环,每次执行都是全新的独立块级作用域,不会被新循环时覆盖,let非常适合用于 for循环声明计数器 i ;
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_38290251/article/details/107576414

posted @ 2024-06-21 11:26  江境纣州  阅读(4)  评论(0编辑  收藏  举报