js预解析

js的预解析:

为什么我们用var定义一个变量a,在这行代码之前打印a却不报错,而是得到undefined?又或者函数为什么可以随意放置,在哪里调用都可以应用,这是什么原理?

其实这样的情况,都是因为JavaScript中有一种机制,就是:“预解析机制”。

1.1   预解析原理

简单来说,预解析就是——在当前作用域下,js在运行之前,会把带有var和function关键字声明的变量先声明,并在内存中安排好。然后再从上至下解析js语句。

  var 预解析

    js 在正常解析之前,会快速的把 script (或者 funciton )中的 var 声明及声明的名字,提升到代码块(作用域)的最前面。

  function 预解析

    js 在正常解析之前,会快速的把 script (或者 funciton )中的 function 及内容提升到代码块(作用域)的最前面,跟在 var 声明之后。

 

1.2          var声明

通过var声明的变量,进行预解析的时候:先声明变量,不管变量有没有赋值,声明时都赋值为undefined。

  事例:

    console.log(a); //undefined

    var a = 1;

    console.log(b); //undefined

    var b = function(){}//注意,这是个函数表达式

 

  事例:

  第1步:

    console.log(a);// undefined,此时读取变量a

    var a = 10;

//解释:在执行代码之前,js会预解析代码,代码中如果有变量声明和函数声明的话,那么便将变量声明和函数声明置顶;

也就是说,以上代码在js运行中,是如下执行的:

  var a;//变量声明置顶设置,但不赋值

  console.log(a); //undefined

  a = 10;//变量在此处赋值。

  第2步:

    console.log(a); //undefined

    console.log(b); //undefined

    var a = 10;

    var b = function(){}//同样是var声明的函数进行置顶设置,但是不赋值;

  第3步:

    var a = 10;

    var a = function(){};

    console.log(a); //function (){}

相当于:

    var a = 10;

    a = function(){};

    console.log(a); //function (){}

    var定义的a,是同一个a,不会产生不同的变量,只是让a改变了值,由数值变成了函数。

反之亦然,

    var a = function(){};

    var a = 10;

    console.log(a); //10

var声明按照赋值顺序执行,同名的var声明,后者的声明不会产生新变量,只是值会覆盖前者。

1.3          function声明

  js 在正常解析之前,会快速的把 script (或者 funciton )中的 function 及内容提升到代码块(作用域)的最前面,跟在 var 声明之后。

  function进行预解析的时候,不仅是声明而且还定义了函数体,在内存中会开辟一块内存空间,存储的是函数体的字符串,但是代码不会执行。只有函数调用以后才执行。

  事例:

  第1步

    console.log(a); //打印结果不是a,而是函数a()的方法体!证明函数a跟在var声明之后被声明的。

    var a = 10;

    function a(){return 100;};

其实相当于:

    var a;

    function a(){return 100;};

    a = 10;

  第2步

    var a = 10;

    function a(){return 100;};

    console.log(a); //10

解释请看上一步的代码解释。

注意:

(1)   同名的var声明和同名的函数声明(不是函数表达式,用function声明的函数),不管二者书写先后顺序,函数声明会覆盖掉var声明的变量(因为它的置顶顺序低于var声明);

(2)   同名的var声明,后者会被忽略;

(3)   同名的函数声明,后者会覆盖前面的(这只是函数声明按自上而下的顺序执行罢了)。

课堂练习,思考一下结果:

var a = 10;

function a(){return 100;};

var a = function (){return 10000;};

console.log(a);

注意问题:

(1)   预解析,不会超出script标签,前面访问不到后面的定义

<script>console.log(a) // 报错</script>

<script>function a(){}</script>

(2)   后面script标签中可以访问呢前面script标签中的js,因为js是从上至下执行的。

(3)   函数内部同名变量的声明高于传入的同名参数

var a = 10;

function fn(a){

   var a = 20;

   console.log(a);//20

}

fn(a);

(4)   函数内参数的声明高于外部同名变量的声明。

var a = 10;

function fn(a){

   console.log(a);//100

}

fn(100);

1.4          预解析应用

var a = 1;

function b(){

    a = 10;

    return;

    function a(){

        console.log(a);

    }    

}

b();

console.log(a);

思考,打印结果?

注意:预解析既可置顶提升变量也可以提升函数。

代码会按照如下情况执行:

var a;

function b(){//注意,函数也会提升

    function a(){//注意,函数也会提升,而不是被return结束掉了。

        console.log(a);

    }    

    a = 10;//注意,作用域链的应用,它的查找顺序是由内而外,就近原则!所以虽然函数a没有被调用过,但是这里的赋值,是赋值给b函数中的a函数的!

    return;

}

a = 1;

b();

console.log(a);

课堂练习:

①   

  var a;

  function a(){ 

    console.log(10); 

  } 

  console.log(a);

②   

  function a(){ 

    console.log(10); 

  } 

  var a;

  console.log(a);

③   

  function a() {

      var b = 1;

  }

  console.log(a);

 

  var a = function() {

      var b = 2;

  };

posted @ 2021-08-05 14:07  小黄耗子  阅读(814)  评论(0编辑  收藏  举报