# 预解析与作用域

# 环境

运行环境 是JavaScript中重要的一个概念,指JavaScript代码运行的地方

  • 宿主环境: 指支持JavaScript运行的平台或软件,一般指浏览器
  • 执行环境: 定义了变量或函数有权访问的其他数据,决定了它们各自的行为
    • 全局环境:整个页面
    • 函数环境:一个函数内部就是一个环境
    • eval()

正因为有了这些环境,在不同环境中声明的变量或函数就有了它的生效范围,这就是作用域:

# 作用域

作用域:作用域即一段代码的作用范围。

# 全局变量

在全局环境(即函数外部)声明的变量,或者没有使用var关键字声明的变量,在任何地方都可以访问得到,拥有全局的作用域。

# 局部变量

在函数环境(即函数内部)声明的变量,参数也是局部变量。只能在函数内部访问得到。

var a=100;
function aa(){
    alert(a);
    var b = 200;
    alert(b);
    c = 1;
}
aa();   // 100 200
alert(a);  //100
alert(b);  //报错
alert(c);

优点:可以提高程序的逻辑性、安全性,可以减少名字的冲突。

# 作用域链

当访问一个变量或函数时,JavaScript会创建变量的一个作用域链,规定了该变量在执行环境中的访问次序:从当前环境开始,依次到包含(外部)环境、下一个包含环境,直到全局环境。

直观表现就是:变量函数的值会从当前作用域寻找,然后逐级地向上级回溯,直至找到变量为止(如果找不到变量,通常会导致错误发生)。

var num = 1;
function aa(){
  var num = 2;
  function bb(){
    var num = 3;
    function cc(){
      num = 4;
      alert(num);	// 4
    }
    cc();
    alert(num);		// 4
  }
  bb();
  alert(num);			// 2
}
aa();
alert(num);				// 1

注意:
不用var声明直接为变量赋值,得到的不是真正的全局变量,它实际是对属性赋值操作。首先,它会尝试在当前作用域链中解析 改变量; 如果在任何当前作用域链中找到改变量,则会执行对改变量属性赋值; 如果没有找到改变量,它才会在全局对象(即当前作用域链的最顶层对象,如window对象)中创造改变量属性并赋值。

# 预解析

JavaScript解析器在运行JavaScript代码的时候会将变量函数提前到当前作用域顶部,再顺序执行。

预解析顺序:

  1. <script> </script>块依次来解析的
  2. 按执行环境来解析
    • 全局环境:打开页面解析
    • 函数环境:调用该函数的时候解析
  3. 遇到关键字var和function时,提前解析到内存中
  4. 如果还有<script> </script>块,再按上述顺序来解析

案例:

  1. 全局环境预解析
  2. 函数环境预解析
  3. 分块解析

预解析案例:

alert(a);   //  undefined
var a = 12;
alert(a);   //  12
alert(b);   //  b is not defined
var num = 10;
function fun() {
    var num
    console.log(num)     // undefined
    num = 100
}
fun()
console.log(fun);   // 函数fun
var fun = 123;
function fun() {
    console.log('Hello javascript');
}
console.log(fun);     // 123