likes
comments
collection
share

预编译和作用域链,搞清js底层执行机制

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

前言

JavaScript 是一种动态和灵活的编程语言,以其独特的执行机制而闻名。在 JavaScript 中,预编译和作用域链是理解代码执行过程的重要概念。

预编译是指在 JavaScript 执行代码之前,浏览器会首先解析代码,创建变量和函数的环境。在这个阶段,JavaScript 会确定变量和函数的声明,并建立作用域链。作用域链则描述了在 JavaScript 中,变量和函数的查找顺序。每个函数都有自己的作用域,作用域链则连接这些作用域,使得内部函数可以访问外部函数中的变量。

理解预编译和作用域链对 JavaScript 开发者来说至关重要,因为这直接影响了变量和函数的可见性、提升(hoisting)的机制以及闭包等高级概念的实现。通过深入研究这些机制,我们可以更好地理解和预测 JavaScript 代码的行为,帮助开发者编写更健壮、稳定的程序。

预编译

预编译和作用域链,搞清js底层执行机制

当我们看见下面这段代码的时候,一定能答得出来打印结果为123,那么加大难度,看下面的问题。

预编译和作用域链,搞清js底层执行机制

那么输出的a到底是全局变量还是函数内的局部变量还是函数内定义的函数呢,就得搞清楚预编译的底层原理了。

预编译的底层原理

对于发生在全局:(执行前必先编译)

  1. 创建一个GO对象
  2. 找变量声明,属性为变量名,值为undefined
  3. 找函数声明,属性为函数名,值为函数体

对于发生在函数体内(执行前必先编译)

  1. 创建AO对象
  2. 找形参和变量声明,属性值为形参和变量名,值为undefined
  3. 形参实参统一
  4. 找函数声明,属性为函数名,值为函数体

当了解到这一点之后我们就可以开始上面题目的剖析了。

首先我们从全局看,创建GO对象,找变量a并赋值为undefined作为属性,再找函数fn赋值函数体为值作为属性,然后开始调用函数,在调用函数之前,我们又创建了一个对象,然后根据以上相同的方式,我们最终可以得到

  GO{
    a: undefined
    fn: func
  }
  AO{
    a: undefined 3 func 2
  }

当打印a的时候结果很自然就是2了,接下来再给出一复杂点的题目

进阶1

预编译和作用域链,搞清js底层执行机制

这个题目在运行前对应的GO和AO对象如下所示

GO{
  fn: function
}
AO{
  a: undefined 1 function
  b: undefined
  c: undefined function
}

最终我们可以得到结果(还得去运行,赋值操作在文中并没有给出)1.function 2.123 3.123 4.function 5.123

预编译和作用域链,搞清js底层执行机制

进阶2

预编译和作用域链,搞清js底层执行机制

答案已经给出,大家可以自行思考

预编译小结

按照我们的说明,以后不管是碰见什么样子的情况,都可以完美解决了,而不是仅限于变量声名提升和函数整体提升,是不是非常的nice呢?

作用域链

在搞懂预编译后,我们再反过头来弄比较简单的作用域链,就很容易了

基本原理

废话不多说,我们先给出一幅图(此图的全局function为a,给错了)

预编译和作用域链,搞清js底层执行机制

它对应的代码如下

预编译和作用域链,搞清js底层执行机制

我们该如何清楚地解释作用域链,才能弄懂为何是先访问自己有的,没有再去访问别人的呢?

最开始我们有一个GO对象存了全局函数a和变量glob,接下来我们探讨a的作用域,a一开始的0位指向GO但是随着a的调用,又创建了AO对象,存了函数b和变量a,0号位指向这里,原来的0号位变为1号位。b函数初始0号位指向a,接下来调用b函数的也同理,最终我们就形成了一条长长的链子。号位小的优先访问,这也就解释了为什么先访问自己的作用域,找不到再去别人的作用域进行访问。

本文小结

通过本文的学习,想必你对预编译和作用域链的性质一定有了更加深入的了解了。

JavaScript 的预编译和作用域链具有以下特点:

  1. 预编译阶段:JavaScript 在执行代码之前会进行预编译阶段,解析代码并创建变量和函数的环境。在这个阶段,变量和函数的声明会被提升至作用域的顶部。
  2. 变量提升:在预编译阶段,变量声明会被提升至当前作用域的顶部,但赋值操作不会提升,因此在声明之前使用变量会得到 undefined。
  3. 函数提升:函数声明会被提升至当前作用域的顶部,因此可以在声明之前调用函数。
  4. 作用域链:作用域链描述了变量和函数的查找顺序,连接了各个作用域。内部函数可以访问外部函数的变量,但外部函数不能访问内部函数的变量。
转载自:https://juejin.cn/post/7366532063342624806
评论
请登录