var
// =============================================var=======================================function foo() {console.log(a);}function bar() {var a = 3;foo();}var a = 2;bar();// 输出a 是2 首先//*** 这里 1.var关键字 存在变量的提升(注意:在函数体中定义变量,就在函数体中进行变量的提升);2.var 声明作用域(是局部变量还是全局变量, 注意:假如在函数体中定义了变量,外部是无法访问到的不过,在函数内(不仅仅在函数内 同时在全局内也可以 直接省略var 操作符) 定义变量时省略var操作符,可以创建一个全局变量,外部可以访问到该变量)*****// 有趣1:在控制台上 直接输入console.log(a) 就会报错 ;同时改变一下写法 就是 console.log(a); var a ===> 控制台输出underfine 没有关键词var 对a 就行 定义 第三 a=3 console.log(a) 虽然 省略var操作符,同时也给他创建一个全局变量// 例子2:function bar() {var a = 3;function foo() {console.log(a);}// 此时 局部变量a 会 覆盖掉 全局变量a 输出3;foo();}var a = 2;bar();// 例子3:在函数内定义变量 而且省略var 这个关键词 是否报错function foo() {b = '123'}foo()console.log(b)
let
//========================let===========================================================if (true) { var name = 'Matt'; console.log(name); } console.log(name); //同时都是 Mattif (true) { let age = 26; console.log(age); } console.log(age); //第一个会是 26 第二个 抛出错误 ReferenceError: age没有定义//****1.在这里,age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let****//2.let也不允许同一个块作用域中出现重复冗余声明这样会导致报错 但是var 进行重复冗余的声明不会报错。var a; var a; // 不报错let age; let age; // 报错//3.暂时性死区--- let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升// name会被提升console.log(name); // undefinedvar name = 'Matt'// age不会被提升console.log(age); // ReferenceError:age没有定义let age = 26;// 在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError
var和let 混淆
//在使用var的时候,最常见的问题就是对迭代变量的奇特声明和修改 //可以用宏任务的角度理解它for (var i=0;i<5;i++){setTimeout(()=>console.log(i),1000) // 输出55555}//之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑时,所有的i都是同一个变量,因而输出的都是同一个最终值var i = 0;if (i < 3) {setTimeout(() => {console.log(i)}, 0)}i++;if (i < 3) {setTimeout(() => {console.log(i)}, 0)}i++;if (i < 3) {setTimeout(() => {console.log(i)}, 0)}i++;if (i < 3) {setTimeout(() => {console.log(i)}, 0)}//========================================================================================for (let i=0;i<5;i++){setTimeout(()=>console.log(i),1000) // 输出01234}//而在使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例,所以console.log输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值
用同步、宏任务理解:
- 当同步 和宏任务同时存在的时候,执行栈首先执行同步任务,当同步任务执行完毕后 在执行宏任务。
- 当var i=0满足了i<3,看到setTimeout 是异步任务 ,JavaScript会将setTimeout 丢到消息队列那里排队。再执行i++;
- 当i =3的时候不满足i<3的循环条件后,持续执行栈中已经执行完了 所有同步任务 ,会将消息队列的通过事件循环拉到执行栈中执行 此时 i已经 等于3了 所以 输出来都是3.
