封闭是每个开发人员都应该知道的JavaScript的非常重要的部分。但是,这个话题通常成为初学者的真正挑战,并且很难理解。在本文中,我想以一种非常简单的方式解释JavaScript中的关闭。
要了解关闭,您需要知道三个主要概念:
ðScope
ð〜词汇环境
ð〜闭合本身
范围
范围 是代码的一部分,您可以使用变量,函数或对象。换句话说,这是该项目“看到”的代码的一部分。
大多数时候(让我们假装var
关键字不存在),范围是Curly Brackets -{...}
中的代码块。
这不是完全正确的,但是要保持简单,我们可以说每个功能,还可以说if
,for
,while
等的代码块(当使用let
或const
变量时)是一个新的本地范围。
在JavaScript中,有2个主要范围:
-
全局范围 - 在函数或代码块之外声明的变量可以在代码中的任何地方使用。它们是全球的。
-
本地范围 - 如前所述,函数内部的变量(函数范围)或代码块(块范围)只能在该块内使用。
让我们看一个例子。
正如我们所看到的,playerHealth
变量在全局范围中,因此我们可以在全球范围内和函数内使用它。但是damageFromMonster
变量在函数中声明,这意味着它在本地范围内。这就是为什么,当我们尝试在功能外访问它时,我们会收到错误。
此示例还表明,不同的范围可以相互作用。此外,本地范围可以访问外部范围的变量。这使我们了解了“词汇环境”的概念。
词汇环境
词汇环境 是一种数据结构,可在当前执行上下文中存储有关变量,函数和其他对象的信息。这是一个无形的对象,用于JavaScript中每个代码或功能的每个块。它仅在代码执行过程中存在于计算机的内存中,因此无法物理看到。
此对象由两个部分组成:
-
当前范围中具有变量的对象,
-
引用父词法环境。
让我们回到上一个示例。我们有2个词汇环境。
global ,它没有对父词法环境的引用。
local ,指的是全局词汇环境。
我想强调,上面的示例不是真实的代码,而只是试图在视觉上想象词汇环境对象的外观。也必须注意,monsterAttack
函数的局部词汇环境不是在我们声明函数时创建的,而是当我们调用它时(monsterAttack()
)。这是理解关闭的关键点,我们将接下来讨论。
闭合
关闭 在JavaScript中 - 这是一个功能“记住”其创建其词汇环境的功能。这意味着即使在外部代码完成执行后,函数也可以访问外部变量。
换句话说,在调用函数时,建立了其词汇环境,在调用时存储当前变量值,并引用其外部环境。这允许该函数在声明时“查看”可访问的变量。
的确,起初这个概念似乎有些混乱。但是,实际上,一切都变得更加清晰。
让我们看一个例子。
想象我们我们在视频游戏中。在游戏的编辑中,我们创建一个角色。让我们选择一个向导为我们分配名称的向导(name
)。该向导将立即具有基本咒语(castSpell
),以及100个法力(mana
)的使用。这种字符的创建可以用以下函数表示。
当我们单击“创建”按钮时,会创建一个字符,并且可能看起来像这样:
在这一点上,将创建createWizard
函数的词汇环境。
当此功能完成执行时,其词汇环境就会消失,但是由于castSpell
函数的闭合,某些部分(例如mana
和name
变量)被“记住”。
之后,我们使用法术执行第一次攻击。
在这一点上,将创建另一个词汇环境,现在为castSpell
函数(存储在lightWizard
变量中)。这个环境将存在于使用lightWizard
字符创建的词汇环境中,因此它将引用它及其变量(name
和mana
)。
随着下一次攻击,法力将减少。这是因为在新的咒语演员表(castSpell
)中创建了一个新的lightWizard
词汇环境。该环境将包括当前的法力值,即80。在随后的攻击之后,仅保留70个,依此类推。
现在,一个新玩家出现在游戏中。他还使用编辑器并创建一个新的向导。
对于此字符,创建了一个新的词汇环境,这与前一个名称不同。
然后,两个向导之间的战斗开始了。伏地魔用完整的100法力攻击哈利。
哈利罢工,但自从他已经使用了一些法术力以来,他的力量较小。
您现在可能意识到,每次攻击都会创建一个新的词汇环境,存储当前数据,包括其余的mana
。
即使两个向导都是使用相同的createWizard
函数创建的,但它们的执行上下文也不同。每个人都有自己的独立变量。因此,当使用createWizard()
创建新的向导时,您总是从100魔法开始。
这个示例非常基本,但说明了核心概念。我选择了这种方法来避免复杂的解释,并专注于这个重要而有趣的话题的主要思想。
我希望这篇文章能激发您的兴趣,并鼓励您了解有关关闭的更多信息。