JS作用域与预解析

作用域

JavaScript(es6前)中的作用域有两种:

  • 全局作用域
  • 局部作用域(函数作用域)
全局作用域

作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。

局部作用域

作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。

变量的作用域

在JavaScript中,根据作用域的不同,变量可以分为两种:
  • 全局变量
  • 局部变量
全局变量

在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。

  • 全局变量在代码的任何位置都可以使用
  • 在全局作用域下 var 声明的变量 是全局变量
  • 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
局部变量

在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)

  • 局部变量只能在该函数内部使用
  • 在函数内部 var 声明的变量是局部变量
  • 函数的形参实际上就是局部变量
全局变量和局部变量的区别
  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

作用域链

只要是代码都在一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在[内部函数可以访问外部函数变量]的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链。

作用域链:采取就近原则的方式来查找变量最终的值。

案例一:

function f1() {
    var num = 123;
    function f2() {
        console.log( num );
    }
    f2();
}
var num = 456;
f1();          // 打印结果:123

案例二:

var a = 1;
function fn1() {
    var a = 2;
    var b = '22';
    fn2();
    function fn2() {
        var a = 3;
        fn3();
        function fn3() {
            var a = 4;
            console.log(a); //a的值 ?
            console.log(b); //b的值 ?
        }
    }
}
fn1();        //a = 4 ,  b ='22' 

## 预解析

预解析的相关概念

JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。

JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。

  • 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。

  • 代码执行: 从上到下执行JS语句。

    预解析会把变量和函数的声明在代码执行之前执行完成。

    预解析也叫做变量、函数提升。

变量预解析

变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。

案例一

 var num = 10
 fun()
 function fun(){
   console.log(num);    // 结果undefind
   var num = 20
  }

// 相当于以下代码

var num 
function fun(){
     var num
     console.log(num);    // 因此打印的结果为 undefind
     num = 20
  }
num = 10 
fun()   

案例二:

 var num = 10
 function fun(){
   console.log(num); // undefined  与案例一相同
   var num = 20;
   console.log(num);  //20
   }
 fun()

//相当于以下代码
  var num
   function fun(){
      var num 
      console.log(num);  // 因为在函数内 有一个 未赋值的num 变量 根据就近原则 所以是undefined
      num = 20
       console.log(num); // 20
         }
   num = 10;
 fun()

案例三:

 var a = 18;
 f1()
 function f1(){
     var b = 9;
     console.log(a);  // undefined
     console.log(b);  // 9
     var a ='123'
 }
// 相当于以下代码
 var a 
 function f1(){
     var b
     var a
     b = 9
     console.log(a);
     console.log(b);
     a = '123'   
 }
a = 18
f1()

案例四:

 f1();
 console.log(c);        // 9
 console.log(b);        // 9
 console.log(a);        // Uncaught ReferenceError: c is not defined
 function f1(){
     var a = b = c = 9;      // 这个地方 b和c都是相当于直接赋值,没有声名,所以是全局变量
     console.log(a);   // 9
     console.log(b);   // 9
     console.log(c);   // 9
 }

// 相当于以下代码
function f1(){
    var a                // 这里  a 是局部变量, b与c 都是全局变量。
        a= b = c = 9
        console.log(a);  // 9
        console.log(b);  // 9
        console.log(c);  // 9 
}  
f1()
console.log(c);         // 9
console.log(b);         // 9
console.log(a);         // 9

拓展:

在函数内以 var a = b = c 这种形式进行变量声名时,a是函数内部变量,b和c都是全局变量。

function fun(){
    var a=b=c=1
    console.log(a);  // 1
}
fun()
console.log(b);     //  1
console.log(c);     //  1

posted @ 2020-03-13 14:53  ymzii  阅读(137)  评论(0编辑  收藏  举报