变量的预解析

嗨嗨嗨,我来啦,今天我们一起谈论一下变量的预解析~~

预解析呢,也被称为预解释;他对于我们初学者来说,还是蛮重要的,因为他涉及到了我们js代码的执行机制。“预解析”,这个“预”,我们会联想到“预备”、“预先”;而javascript 是一个解释型语言,所以可以理解为在代码开始执行之前,会对代码进行通读解释,然后在进行执行。所以,当我们写完代码,打开浏览器的时候,代码已经执行了,或者说这个解释的过程已经过去了,那么,这个过程,他解释了什么内容呢?

什么情况预解析

 1、var关键字

在代码执行之前,会把代码里面所有的 var 关键字声明的变量提升

比如说

console.log(num) // undefined
var num = 100

在这个代码块中,运行console.log(num)之前;会将页面整个代码通读解释一下,看是否有var关键字;我们发现是有的,所以在代码执行之前,先告诉浏览器num这个变量可以使用,只不过不赋值;也就是我们常说的声明提前;所以上面的两行代码,其实等价于

 var num
 console.log(num)
 num = 100

 2、声明式函数

在代码执行之前,会把代码里面的 声明式函数的变量 提升,并且给这个变量赋值为一个 函数的地址

举个例子

fn()
function fn() {}

在代码fn()执行之前,浏览器已经知道了 fn 变量可用;并且 fn 变量的值是一个函数的地址;这些是浏览器已经通读解释好了的,所以这个时候,在function fn() {}上方调用函数是没有问题的,这也是声明式函数可以在上方调用的原因。

值得注意的是赋值式函数

赋值是式函数按照 var 关键字的解析规则解析

比如说:

fn()
var fn = function () {}

在代码执行之前,浏览器先通读解释,遇见了var关键字,知道了 fn 这个变量可用,仅此而已
在执行fn()这句代码的时候,fn 只是一个变量,还没有赋值,是 undefined

console.log(fn)//undefined
fn()
var fn = function () {}

但是()是函数执行,所以fn()这样子,是把 fn 当作函数来执行了;那么就会报错 fn is not a function!!所以赋值式函数是不能在上方调用的,因为那个时候,他还不是一个函数。

函数预解析

函数内部的预解析,是比较常见的,我们通过三个案例来更清楚的认识了解它。

案例一:

fun()
var fn = function () {
 console.log('我是 fn 函数')
}
function fun() {
 console.log('我是 fun 函数')
}
fn()
fn = 100
fn()

上述代码,是怎样运行的呢?首先,在代码执行之前,我们先预解析:

1. 我们找到了var关键字,所以知道全局声明一个 fn 变量可用

2. 我们看到了声明式函数,所以知道全局声明一个 fun 变量可用,并且这个变量的值是一个函数的地址

3. 预解析完成,开始执行代码

   3-1、fun() 这个代码执行,因为我们上方已经预解析知道fun这个变量可用,并且是一个函数地址,所以直接执行这个函数,控制台打印出 “我是 fun 函数”

   3-2、然后执行fn = function () {console.log('我是 fn 函数')}这块代码,给fn赋值;把一个函数的地址给到了 fn 这个变量   

   3-3、再之后,执行 fn()。可以直接调用函数,控制台打印“我是 fn 函数”

   3-4、紧接着,执行fn = 100;也就是给 fn 这个变量重新赋值为 100

   3-5、最后执行 fn()这行代码 那么就会报错 fn is not a function

案例二:

  fn()
  function fn() {
   console.log('我是一个 fn 函数')
  }
  fn()
  var fn = 100
  fn()

这个案例中,变量名和函数名重复了,那应该是什么样子的呢?   

我们先预解析

   1. 首先,我们看到了声明式函数,所以全局声明一个 fn 变量可用,并且赋值为一个函数的地址

   2. 紧接着,我们看到了var关键字,所以全局声明一个 fn 变量可用;请注意这个没有赋值

      但是我们在第一步的时候,已经知道有一个fn变量可用;所以第二句话就没有什么用了。

   3. 预解析完成,开始执行代码

         3-1、我们代码第一步执行fn();此时 fn() 是一个函数的地址,执行函数

         3-2、 我们代码第二步执行fn();此时fn() 还是一个函数的地址,函数执行

         3-3、 我们代码第三步,执行fn = 100;给 fn 从新赋值,赋值为 100;从此时开始,fn不是一个函数了,是一个数值

         3-4、我们代码第四步执行fn();把数值当成函数,就会报错 fn is not a function

所以当函数名和声明的变量名同名的时候,var 的声明就没有意义了

 案例三:


function fn(a) {
   console.log('我是 fn 函数')
   a()
   function a() {
    console.log('我是函数 a')
   }
  }
  fn(10)

这个案例,我们聊一下函数在执行阶段,都做了哪些事情

首先我们要明确一件事情,那就是预解析会解析函数外部的内容,不会解析函数内部的内容

   那么,我们回顾一下函数的执行过程

1. <!--*按照函数名称的地址找到函数*-->

2. <!--*行参赋值*-->

3. <!--*函数内部的代码进行预解析*-->

4. <!--*把函数体内存储的代码拿出来执行一下*-->

  然回顾了函数的执行过程之后,我们来分析上方案例三的代码,首先 ,全局预解析

​    1.在全局下,我们看到了声明式函数fn,所以知道先 声明一个 fn 变量可用,并且 fn 的值是一个函数地址

​    2.预解析完成,开始执行代码

​    2-1、 执行这行代码fn(10);然后就是函数的执行过程

​    2-2、 函数的执行过程

​    2-2-1、形参赋值 , 先给 a 赋值为一个数字 10

​    2-2-2、函数内部的代码进行预解析,声明一个 a 变量可用,并且赋值为一个函数的地址;所以函数体内的代码在一开始执行的时候 a 就是一个函数地址

​        2-3、 函数体内的代码执行,也就是执行a()这行代码,因为我们在2-2-2的时候,a就是一个函数地址了,所以我们会在控制台打印*'我是函数 a'*

 预解析的无节操

不管 if 条件是否成立,代码块里面的 var 都会进行声明

 return 后面的代码虽然不会执行,但是会进行预解析

举个例子

 function fn() {
   console.log(num1)
   return
   var num1 = 100
  }
  fn()
  console.log(num)
  if (false) {
   var num = 100
  }

在上述代码中,我们会先去预解析

 首先,我们看到了声明式函数,所以全局声明一个 fn 变量可用,并且赋值为一个函数的地址

 紧接着,我们看到了var关键字,所以全局声明一个 num 变量可用

 预解析完成,开始执行代码

 3-1、先执行fn()这行代码,然后就是函数的执行过程

 3-1-1、直接就是函数内部的预解析,正常情况,return后面的代码是不执行的,但是预解析他没有节操,还是大大咧咧的开始进行自己的骚操作;声明了一个变量num1可用

  执行下一行代码console.log(num);因为在预解析的时候,我们已经知道有一个num变量可用;所以结果是undefined

  因为选择分支结构中,条件表达式为false,所以不会再进行下面的num赋值操作了。

这个就是预解析的无节操,概括的说,就是上述的两点——

不管 if 条件是否成立,代码块里面的 var 都会进行声明

return 后面的代码虽然不会执行,但是会进行预解析

今天我们就聊到这里了,大家加油,我们下次再见~~

*  获取千锋教育学习视频资料+源码笔记 ,进学习交流群

      请添加下方微信(备注CSDN推荐)

​​​​​​​

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值