宝哥软件园

JavaScript中吊装的详细说明(变量提升和函数声明提升)

编辑:宝哥软件园 来源:互联网 时间:2021-09-03

本文主要介绍JavaScript中提升(变量提升和函数声明提升)的相关内容,并分享给大家参考学习。以下就不多说了。我们来看看详细的介绍。

如何将函数声明/变量“移动”到作用域的顶部。

术语“提升”在许多JavaScript博客文章中用于解释标识符的解析。实际上,术语“提升”是用来解释变量和函数声明如何被提升到函数或全局范围的顶部。在任何JavaScript文档中都找不到这个术语。当我们说“吊装”时,我们只是用它的字面意思作为比喻。

如果你对JavaScript范围是如何工作的有一个基本的了解,那么对提升的更深入的理解将有助于你建立更强的基础知识。(愚人码头注:变量提升和函数声明提升作为JavaScript中的一个通用概念,在前端开发面试中经常被问到或者出现在前端开发试题中。可见,了解吊装是很重要的。)

为了更好的理解基础知识,我们来复习一下“吊装”到底是什么意思。另外,提醒大家,JavaScript是一种解释性语言,不同于编译语言,这意味着JS代码是逐行执行的。

考虑以下示例:

console.log(未声明);//print ' undefined ' var notyeddedclared='现在它被声明了';吊装();函数提升(){ console . log(notyet declared);//打印“undefined”var notyet declared=“声明方式不同”;console.log(未声明);//打印“不同声明”}分析上述示例代码后,提出了几个问题:

第6行,为什么这个函数在声明之前可以被访问?在第一行中,没有抛出错误,因为变量notyetdeclared此时不存在?第四行,未声明,已在全局范围内声明。为什么打印第九行时还是未定义?JavaScript非常符合逻辑,所有这些奇怪的问题都有明确的解释。

我们从头开始解释,当代码在JavaScript中执行时,运行时上下文就建立了。JavaScript中运行时上下文主要有两种类型——全局运行时上下文和函数运行时上下文(注意:要特别注意运行时上下文不同于我们通常所说的上下文,后者指的是作用域,而通常的上下文指的是这个的值)。因为JavaScript是基于单线程执行模型的,所以一次只能执行一段代码。

对于我们上面的代码,这个过程如图所示:

调用上述示例代码的堆栈:

程序从堆栈上的全局运行时上下文执行。调用延迟()函数时,新的函数运行时上下文被推送到堆栈上,全局运行时上下文被挂起。提升()执行完成后,从栈中弹出提升()运行时上下文,恢复全局运行时上下文。这个过程是不言自明的,但是它并没有真正解释我们在执行示例代码时看到的异常。当运行时上下文跟踪代码的执行时,词法环境跟踪标识符到特定变量的映射。词法环境基本上是JavaScript作用域机制的内部实现。一般来说,词法环境与JavaScript代码的特定结构相关联,例如函数或for循环代码块。每当创建一个函数时,对它创建的词法环境的引用将在名为[[环境]]的内部属性中传递。

所有这些术语涵盖了一个简单且非常符合逻辑的概念。让它分解。词法环境是一个有趣的名字,用来跟踪代码块中的变量和函数。除了跟踪局部变量、函数声明和参数,每个词法环境还跟踪其父词法环境。因此,上面的示例代码将在JavaScript引擎中这样解析。上述代码的词法环境如图所示:

注意:

如果理解有问题,请查看以下三篇文章:

深刻理解JavaScript中的范围和上下文;分析JavaScript核心概念的范围和闭包实例;为了在词法环境中解析标识符,JavaScript引擎将检查当前环境的引用。如果没有找到引用,请使用[[环境]]移动到外部环境。这将继续,直到找到标识符或引发“未定义”错误。

基本上,JavaScript代码分两个阶段执行。第一阶段注册当前词法环境中的所有变量和函数声明。完成后,第二阶段的JavaScript执行就开始了!

所以第一阶段要详细说明:分两步起作用。

扫描当前函数声明中的代码。函数表达式和箭头函数被跳过。对于每个发现的函数,都会创建一个新函数,并使用函数名将其绑定到环境。如果标识符的名称已经存在,其值将被覆盖。然后扫描当前环境的变量。找到var定义的变量和其他函数之外的变量,注册一个值被初始化为undefined的标识符。如果标识符存在,该值将保持不变。注意:let和const用于定义块变量,与var略有不同。在另一篇文章中了解更多信息。

既然您已经对词法环境的基本概念有了一定的了解,那么让我们回到示例代码并解释这些问题。

设置全局上下文时,会扫描环境,并将提升()函数附加到标识符上。然后,在下一步中,注册变量notyetdeclared,并将其值初始化为undefined。按照此步骤继续理解代码。

现在让我们解释一下示例代码中提出的三个问题:

第6行,为什么这个函数在声明之前可以被访问?

在第一阶段,提升()功能已在标识符中注册。当JS代码在第二阶段的全局执行上下文中开始执行时,会找到提升的词法环境,并在定义之前找到函数。

在第一行中,没有抛出错误,因为变量notyetdeclared此时不存在?

同样,notyetdeclared用标识符注册,并在阶段1中初始化为undefined,因此不会引发错误。

最后,

第四行,未声明,已在全局范围内声明。为什么打印第九行时还是未定义?

现在我们进入功能提升的环境。在第一阶段,notyetdeclared被注册并初始化为undefined,因为notyetdeclared的变量还没有在这个词法环境中注册。如果第12行不包含var关键字,那么情况就不同了。

我希望现在可以清楚地看到,在JavaScript中,提升只是我们用来解释背后原理的一个点。从技术上讲,函数和变量不会移动。

摘要

以上就是本文的全部内容。希望本文的内容能给你的学习或工作带来一些帮助。有问题可以留言交流。谢谢你的支持。

更多资讯
游戏推荐
更多+