• 每个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上
  • 全局上下文是最外层的上下文;
  • 在浏览器中,全局上下文就是我们常说的 window 对象;
  • 上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数;
  • 当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文ಖ会弹出该函数上下文,将控制权返还给之前的执行上下文;
  • 上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain),其决定了各级上下文中的代码在访问变量和函数时的顺序
  • 活动对象最初只有一个定义变量:arguments;
  • 全局上下文的变量对象始终是作用域链的最后一个变量对象;

作用域链增强

  • try/catch语句中的catch块
    • catch 语句而言,则会创建一个新的变量对象
  • with语句
    • 语句会向作用域链前端添加指定的对象

变量声明

  • var作用域声明

    • 使用var声明变量时,变量会被自动添加到最接近的上下文;
    • 如果变量未经声明就被初始化了,那么它就会自动被添加到全局上下文
    • var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前
    • 通过在声明之前打印变量,可以验证变量会被提升。声明的提升意味着会输出 undefined 而不是Reference Error
      1
      2
      3
      4
      5
      6
      7
      var name = "Lacus";
      //等价于
      name = "Lacus";
      var name;
      //---------------------
      console.log(msg);//underfined
      var msg = "boy";
  • let块级作用域

    • 块级作用域由最近的一对包含花括号{}界定
    • if 块、while 块、function 块,甚至连单独的块也是 let 声明变量的作用域;
    • let 在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重复的 let 声明会抛出 SyntaxError;
    • let 的行为非常适合在循环中声明迭代变量。使用 var 声明的迭代变量会泄漏到循环外部
    • let 在 JavaScript 运行时中也会被提升,但由于“暂时性死区”(temporal dead zone)的缘故,实际上不能在声明之前使用 let 变量。
      1
      2
      3
      4
      5
      for(var i=0;i<10;i++){}
      console.log(i);//10

      for(let j=0;i<10;j++){}
      console.log(j);//ReferenceError: j没有定义
  • const常量声明

    • const 声明的变量必须同时初始化为౼个值,一经声明,在其生命周期的任何时候都不能再重新赋予新值
    • const 声明只应用到顶级原语或者对象