var

  1. // =============================================var=======================================
  2. function foo() {
  3. console.log(a);
  4. }
  5. function bar() {
  6. var a = 3;
  7. foo();
  8. }
  9. var a = 2;
  10. bar();
  11. // 输出a 是2 首先
  12. //*** 这里 1.var关键字 存在变量的提升(注意:在函数体中定义变量,就在函数体中进行变量的提升);2.var 声明作用域(是局部变量还是全局变量, 注意:假如在函数体中定义了变量,外部是无法访问到的不过,在函数内(不仅仅在函数内 同时在全局内也可以 直接省略var 操作符) 定义变量时省略var操作符,可以创建一个全局变量,外部可以访问到该变量)*****
  13. // 有趣1:在控制台上 直接输入console.log(a) 就会报错 ;同时改变一下写法 就是 console.log(a); var a ===> 控制台输出underfine 没有关键词var 对a 就行 定义 第三 a=3 console.log(a) 虽然 省略var操作符,同时也给他创建一个全局变量
  14. // 例子2:
  15. function bar() {
  16. var a = 3;
  17. function foo() {
  18. console.log(a);
  19. }
  20. // 此时 局部变量a 会 覆盖掉 全局变量a 输出3;
  21. foo();
  22. }
  23. var a = 2;
  24. bar();
  25. // 例子3:在函数内定义变量 而且省略var 这个关键词 是否报错
  26. function foo() {
  27. b = '123'
  28. }
  29. foo()
  30. console.log(b)

let

  1. //========================let===========================================================
  2. if (true) { var name = 'Matt'; console.log(name); } console.log(name); //同时都是 Matt
  3. if (true) { let age = 26; console.log(age); } console.log(age); //第一个会是 26 第二个 抛出错误 ReferenceError: age没有定义
  4. //****1.在这里,age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let****
  5. //2.let也不允许同一个块作用域中出现重复冗余声明这样会导致报错 但是var 进行重复冗余的声明不会报错。
  6. var a; var a; // 不报错
  7. let age; let age; // 报错
  8. //3.暂时性死区--- let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升
  9. // name会被提升
  10. console.log(name); // undefined
  11. var name = 'Matt'
  12. // age不会被提升
  13. console.log(age); // ReferenceError:age没有定义
  14. let age = 26;
  15. // 在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError

var和let 混淆

  1. //在使用var的时候,最常见的问题就是对迭代变量的奇特声明和修改 //可以用宏任务的角度理解它
  2. for (var i=0;i<5;i++){
  3. setTimeout(()=>console.log(i),1000) // 输出55555
  4. }//之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑时,所有的i都是同一个变量,因而输出的都是同一个最终值
  5. var i = 0;
  6. if (i < 3) {
  7. setTimeout(() => {
  8. console.log(i)
  9. }, 0)
  10. }
  11. i++;
  12. if (i < 3) {
  13. setTimeout(() => {
  14. console.log(i)
  15. }, 0)
  16. }
  17. i++;
  18. if (i < 3) {
  19. setTimeout(() => {
  20. console.log(i)
  21. }, 0)
  22. }
  23. i++;
  24. if (i < 3) {
  25. setTimeout(() => {
  26. console.log(i)
  27. }, 0)
  28. }
  29. //========================================================================================
  30. for (let i=0;i<5;i++){
  31. setTimeout(()=>console.log(i),1000) // 输出01234
  32. }
  33. //而在使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例,所以console.log输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值

用同步、宏任务理解:

  1. 当同步 和宏任务同时存在的时候,执行栈首先执行同步任务,当同步任务执行完毕后 在执行宏任务。
  2. 当var i=0满足了i<3,看到setTimeout 是异步任务 ,JavaScript会将setTimeout 丢到消息队列那里排队。再执行i++;
  3. 当i =3的时候不满足i<3的循环条件后,持续执行栈中已经执行完了 所有同步任务 ,会将消息队列的通过事件循环拉到执行栈中执行 此时 i已经 等于3了 所以 输出来都是3.