JS中的预解析机制详解

1、概念

  1. JS的语言特性解释型语言
    • 没有编译过程 ,但在执行时,有翻译行为 ,让:计算机能理解我们写的代码
    • 所以js产生了预解析的机制
  2. 预解析包含
    a. 变量声明提升函数声明提升两部分
    b. 面试时:也可能会分开问这两个,预解析是一个很广泛的概念,包含了这两部分的内容

2、预解析功能

2.1、语法检查

  1. 语法检查
    • 解释器准备解释代码前,会预先对所有的Js代码进行语法检查,如果发现存在语法错误,那么所有代码都不会执行
    • 然后报出语法错误语法错误的级别也是最高的
  2. 语法错误示例
function (){}  // 函数创建时没有添加函数名 
var a = 10// 错用了中文符号 这里应该为英文的分号;
    ... 等等

2.2、声明提升

  1. 解释
    • 为了拥有更好的性能,代码在执行的时候,会把所有的声明行为放在代码解释的最前方;
    • JS中所有的变量声明行为、函数声明行为都需要和内存进行交互操作
      • 这个交互操作叫做:I(input)/O(output)操作
    • 在代码开始解释前,也就是预解析时,会把所有涉及内存的io操作统一完成,来加快我们的内存操作速度,

也就是:

  • 每次都单独开启放入变量等操作会比较浪费时间
  • 那么一次性开启放入所有,在一次性结束,对整体的性能是比较好的,也比较省时
  1. 声明提升会导致
    • 我们看到的代码,并不是真实代码的摆放位置
    • 因为无论把声明的变量函数代码写在哪里,都会在执行代码之前给提升到最前面去,然后优先执行
  2. 示例:
    • var a = 10;无论是声明的位置在哪里,都会提前到所有代码最前面,提前进行声明

3、变量声明提升详解

解释:

  • 代码执行分成两个阶段:1、预解析 2、代码翻译并执行
  • 注意:这里的代码翻译是指计算机翻译成计算机语言执行(这里可能不完全对,理解即可)
  1. 预解析
    • 第一步:语法检查,检查语法是否出错,如果有错误,代码则全部不会执行
    • 第二步:声明提升
示例:var a = 10 
// 1、预解析规则中会把变量声明拆分成两个部分:
	// 1)var a;  ==> 声明变量行为,会发生声明提升,位置放在预解析;  
    // 2)a = 10; ==> 赋值行为,放置在书写位置                         
// 2、解释:
    // 1)我们看到的代码是var a = 10; 实际是:a = 10,原位置保留
    // 2)var a 是在预解析的位置去执行了,在实际执行代码的过程中,下面的代码只存在赋值行为,
  1. 代码翻译并执行

4、变量声明提升详解

解释:

  • 代码执行分成两个阶段:1、预解析 2、代码翻译并执行
  • 注意:这里的代码翻译是指计算机翻译成计算机语言执行(这里可能不完全对,理解即可)
  1. 预解析
    • 第一步:语法检查,检查语法是否出错,如果有错误,代码则全部不会执行
    • 第二步:声明提升
    • 注意:
      • 函数声明提升会把整体函数都提升到预解析部分去,但是!赋值式函数不是整体提升
      • 这里要注意:用var声明变量后的提升,只是提升了变量声明部分,函数赋值部分没有进行提升
function foo(){
     alert("hello world"); // 虽然是写在这里的,但是会整体提升至最前面的预解析部分
 } 
  1. 代码翻译并执行

5、声明提升的影响

5.1、变量声明提升的影响

// 1、先确定一个报错机制:变量没有声明直接使用会报错(也就是:引用错误) => 这里并未声明变量b,所以直接引用报错
        console.log( b );

// 2、因为声明提升机制:我们在变量声明之前使用变量不会报错,只是打印变量的结果为undefined 
   // 1)代码是从上到下执行的,这里先引用了,然后再声明赋值,但实际的运行顺序为:
     // 1、var c 被放置在预解析的位置
     // 2、代码运行到console.log( c ),变量c只是声明了,但还未执行到赋值的代码块
     // 3、所以打印结果为undefined,并不会报错
        console.log( c );  
        var c = 10; 

// 3、注意:这个机制会带来很多问题,所以:应该遵循`先声明后调用`的原则来使用变量
    // 1)示例:
                   console.log( c + 10 ); 
                   var c = 10
    // 2)解释:这里的计算结果为NaN,会导致运算错误,如果这个变量后面还有运算的话,会很麻烦,导致很多错误,所以一定要遵循:先声明后调用的原则!

5.2、函数声明提升的影响

// 1、对`声明式函数`的影响:
   // 1)这里先调用是可以执行的,因为函数的声明提升是整体提升到最前面的预解析的
        foo(); 
   // 2)不会报错
        function foo(){
            alert("foo函数调用!") 
        }

// 2、对`赋值式函数`的影响:
   // 1)赋值式函数步不可以在前方调用!!! 
   // 2)因为:用var声明变量后的提升,只是提升了变量声明部分,函数赋值部分没有进行提升 => var poo,此时调用poo(),由于不是整体提升的,
   //         poo会被当成变量,而变量使用(),会报错 => Uncaught TypeError: poo is not a function,poo不是一个方法/函数
   // 3)示例:
              poo();  // poo 此时是undefined,因为声明为赋值
              var poo = function(){
                alert("poo函数调用!") 
              }

6、补充

6.1、预解析只会在当前script标签中提升

1、解释:
       1)预解析只会在当前script标签中提升,无法提升下一个script的内容
       2)访问和声明提升是两码事,访问是可以跨的,提升是不行的,访问是可以访问另一个script的函数名
2、示例:
       解释:预解析只管在同一个script进行提升 只能提升到当前script的最上面
<script>
        aa()
        function aa(){
           console.log("age is 100")
        }
</script>

<script>
    // 上面的调用是不管这里的
        function aa(){
        console.log("age is 200")
      }
</script>

6.2、函数内部变量/函数提升的局限

function test(a,b){
   var result = a+b
   console.log(result) // 调用函数后,函数内部可以正常打印结果
}
test(1,2)
console.log(result) // 这里会报错 => 因为函数内部resul变量只能提升到函数内部的最上面,如果在函数内部定义的var或者是函数内部定义的函数也只能提升到函数的最上面

6.3、函数内部声明提升

提升的顺序是:
           1、把var name提上到函数最前面
           2、打印name => 此时是undefined
           3、赋值"小明"给name
           4、再次打印name => 此时结果为"小明"
<script>
         function test(){
            console.log(name); // undefined
            var name = "小明"
            console.log(name) // "小明"
         }
         test()
</script>
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值