likes
comments
collection
share

JS的底层小知识(二):预编译

作者站长头像
站长
· 阅读数 38

前言

上篇文章简单的给各位讲了一下作用域,相信大家都有另一个清晰的认识,OK,那么我们继续往下走,一起来探索一下秘书是怎样工作的吧!

JS的底层小知识(二):预编译

声明提升

在此之前,我们先简单的来了解一下什么是声明提升:

声明提升:在JS中,"声明提升"是指 变量和函数的声明 在代码执行前,会被提升到其所在作用域的最顶部。这并不意味着赋值操作也会被提升,只有声明部分会被提升。

变量声明提升

对于使用var声明的变量,无论它们出现在代码的哪个位置,都会被提升到当前作用域的顶部。但是,变量的赋值操作不会被提升。

就比如以下代码:

console .log(a)
var a = 1

该段代码的输出结果为 undefined,因为在代码执行前,var a 会被提升到全局作用域的顶部。

也就是这样:

var a
console .log(a)
a = 1

函数声明提升

函数声明也会被提升,但是函数是整体提升,也就是说函数会带着函数体内的东西一起被提升当前作用域的顶部。

就比如:

foo(  )
function foo() {
    var b = 1
    console.log(b) 
}

会变成:

function foo() {
    var b = 1
    console.log(b) 
}
foo(  )

注意:let, const 和 函数表达式

使用letconst声明的变量以及函数表达式并不会被提升。为什么呢?

letconst声明的变量,严格遵循块级作用域的规则,不会提升,他们会在词法环境中,划出一块属于自己的词法作用域,声明在哪里,就在哪里。

关于什么是词法作用域,大家可以去我的上一篇文章中查找一下。

而函数表达式是什么呢?就好似这样的代码 var b=function(){},这种只会把变量b的声明提升,不会带上赋予b的函数function

所以它们在定义它们的代码执行之前是不可访问的。

预编译

什么是预编译呢?预编译就好比是一位秘书,而 JS 的编译器 V8 ,就是董事长。编译器(董事长)在执行代码前,肯定会有一位高效能干的秘书(预编译)。所以在你需要执行一段代码输出结果之前,预编译悄然启动,为编译器的执行做好充足的准备,以便编译器能正常顺利的执行并输出结果。

全局的预编译

首先,在你将输出指令发送给进程终端之后,秘书就会开始全局的预编译,下面有请看以下代码:

var gloabal = 100
function fn(a) {
    console.log(a)
    var a = 123
    console.log(a)
    function a() {}//函数声明
    console.log(a)
    var b=function(){}//函数表达式(变量声明)
    console.log(b) 
    function d() {}
    var d = a
    console.log(d)
}
fn(gloabal)

秘书一看到这段代码,就会进行以下操作:

  • 首先,创建一个全局的执行上下文对象( GO
  • 其次,找变量声明,变量名作为GO的属性名,值为 undefined
  • 然后,找函数声明,函数名作为GO的属性名,值为 函数体 function
  • 最后,交给董事长(V8编译器)执行

董事长会一个个从上到下执行,先给gloabal 赋值为 100,然后执行fn(gloabal)函数。此时就要执行fn()函数,而编译总是在执行之前,所以就会开始函数的预编译。

函数中的预编译

好,秘书一看到这段函数体内的代码,就会进行一下操作:

  • 首先,创建一个函数的 执行上下文对象 (AO
  • 其次,找形参和变量声明,将形参和变量名作为AO的属性,值为 undefined
  • 再次,将实参和形参统一
  • 然后,在函数体内找函数声明,将函数名作为AO的属性名,值赋予函数体
  • 最后,交给董事长(V8编译器)执行

那么,秘书的小本本上是怎么记录的呢,也就是说,预编译的过程是什么呢?大家可以根据以上步骤先思考一下,并写出输出的结果,完事之后,来看看秘书的编译过程吧!

//全局的预编译
GO:{
    gloabal:undefined
    fn:function(){}
}
//全局的预编译结束,该到V8编译器执行
GO{
    gloabal:undefined -> 100
    fn:function  -> 调用fn()函数
}
//函数的预编译
(第一步)
AO:{    
       第二步      第三步    第四步
    a:undefined => 100 => function(){} => 123
    b:undefined                      =>function(){} 
    d:undefined        => function(){} => 123 
}
//函数的预编译结束,该到V8编译器执行
AO:{    
                                           执行
    a:undefined => 100 => function(){} => 123
    b:undefined                        =>function(){} 
    d:undefined        => function(){} => 123 
}

所以输出结果为:

JS的底层小知识(二):预编译

看看你的结果和我的一样吗?不一样的话,可以再看看,多思考,多动脑哦,也可以在评论区说出你的疑惑哦

JS的底层小知识(二):预编译

写得不好的地方以及需要修改的地方,欢迎大佬亲临指正昂💞

转载自:https://juejin.cn/post/7373136303179431947
评论
请登录