【问题标题】:Function declarations precedence/overwriting variable declarations? Hoisting? Why?函数声明优先/覆盖变量声明?吊装?为什么?
【发布时间】:2018-02-11 09:54:06
【问题描述】:

片段 1:

var a; // undefined variable named 'a'
function a(foo) { // a function named 'a'
  var foo = "Hello World";
  console.log(foo);
}
console.log(a); // output is: [Function: a], but why not undefined?

片段 2:

function a(foo) { // a function named 'a'
    var foo = "Hello World";
    console.log(foo);
}
var a; // undefined variable named 'a'
console.log(a); // output is: [Function: a], but why not undefined?

我本可以只展示 Snippet 1 来提出这个问题 - 但是我展示这两个只是为了完整性。我也在其中写了一些简短的 cmets。

我的问题是,在这两种情况下,为什么函数声明是“overwriting”/'shadowing' 或在变量声明上采用“precedence”?有人可以解释一下这种行为吗?

我知道,由于“提升”现象,这些在最终结果方面可以说是相同的(从解释器的角度来看),但是 为什么 函数声明或变量声明在被 Javascript 引擎解释/解析时( 创建 阶段)具有优先权?即哪一个被提升到另一个之上?我读过它是函数声明优先于变量声明 - 但是为什么会出现这种情况?

另外,请参考第一个代码 sn-p(但这适用于两种情况),是在第 1 行和第 6 行声明的“a”的内存位置/地址 , 完全相同的?由于“a”在代码的两个位置都表示函数声明,在解析第 1 行和第 6 行后,“a”在其内存位置/地址处的 值是多少在创作阶段?由于函数声明被“提升”在变量声明之上,这是否意味着在第 1 行中,在 创建结束时,'a 的内存地址指向函数对象'a' 执行上下文的阶段?

在两个代码 sn-ps 中,'var a' 是未定义的,所以 why isn't 'a' 在我们到达 执行 阶段时 undefined 的值(它的 执行点从第 6 行开始? ) Javascript 引擎 是否简单地说,“啊,如果我们允许 'var a' '覆盖' 'function a() {...}',它将继续未定义并且因而无法使用。然而,如果我们允许 'a' 表示所述函数,那么至少用户可以调用所述函数(甚至在其声明之前,不会出现引用错误)“。这种情况不太可能发生,但听起来合乎逻辑/理想,也许吧?

所以,我的问题是:

  1. 函数声明覆盖或优先于变量声明的原因是什么?是因为它是 ECMAScript 规范的实现而我们只是接受表面上的东西,还是我们可以解释这种行为?

  1. 如果可能,当这种情况发生在每一步时,有人可以回答记忆中发生了什么吗?

在过去的 8 个小时里,我一直在尝试使用我的直觉(在那里我最终陷入了 JavaScript 其他特性的另一个维度,但这本身就是另一个问题)但我想知道是否有一个简单的或对此行为的具体解释或答案。

任何有助于理解所有这些的帮助将不胜感激。

【问题讨论】:

  • 你在做一组家庭作业吗,因为这个问题是very similar to your other question posted not so long ago
  • 我想我以前从未见过这样的家庭作业问题。我最初计划在这些线程中问这个问题,但它们最终会太长。它是相关的,但与那个问题无关,因此这个单独的线程。任何合并都会混淆并影响对我的查询的完全理解。无论如何,重点不仅是帮助自己,还要帮助将来可能有类似问题的其他人......幸运的是,我还没有找到类似的问题 - 你可以吗?
  • "在两个代码 sn-ps 中,'var a' 是未定义的" - 呃,不是吗?
  • @Bergi 我不想在 sn-p 的 cmets 中写太多。我的意思是,如果 'var a' 在其 OWN 上(并且没有函数 'a'),在执行阶段发生之前,var 将是未定义的,对吗?因为它没有价值……
  • 是的,如果没有函数声明,a 的值将是 undefined

标签: javascript memory functional-programming variable-declaration function-declaration


【解决方案1】:

我的问题是,在这两种情况下,为什么函数声明“覆盖”/“遮蔽”或“优先”于变量声明?有人可以解释一下这种行为吗?

在任一sn-p 中只有一个地方变量a 被赋予了一个值,那就是函数声明。声明var a; 的意思是“我宣布存在一个名为a 的变量”。由于函数声明负责宣布它存在给它一个值,var a; 语句实际上没有任何效果。

事实上,如果我们参考 JavaScript 规范的 Section 10.5.8,我们可以看到这个 var a; 的最终结果实际上是什么都不做,因为 a 变量在 @987654328 时已经声明了处理@声明。

我理解,由于“提升”现象,就最终结果而言,这些可以说是相同的(从解释器的角度来看),但是为什么函数声明或变量声明优先于另一个时它在创建阶段由 Javascript 引擎解释/解析?

这里没有什么“优先”。只有一个变量名为avar a; 没有给a 赋值,所以对a 的值没有影响。

另外,请参考第一个代码 sn-p(但这适用于两种情况),'a' 在第 1 行和第 6 行中声明的内存位置/地址是否完全相同?

a 变量只有一个,它只取一个值,所以这个问题大多是无意义的,但粗略地说,a 变量本身只会存在于一个地方,它只会引用一个值(内存位置),这将是该函数的定义。

由于函数声明被“提升”在变量声明之上,这是否意味着在第 1 行中,在执行上下文的创建阶段结束时,“a 的内存地址”指向函数对象“a”?

我对创建阶段的了解不是很多,但是在这段代码的执行过程中,a 只引用一个值,正如我上面所说的。

在两个代码 sn-ps 中,'var a' 是未定义的,那么为什么在我们到达执行阶段(其执行点从第 6 行开始?)时,'a' 的值不是 undefined? /p>

查看我的第一个和第二个答案。

函数声明覆盖或优先于变量声明的原因是什么?和

正如我所说,它没有“优先”,但 JavaScript 具有函数提升的原因是为了允许人们在函数实际定义之前从代码中的一行调用函数,类似于其他主要语言就像 C# 和 Java 一样。

如果可能,有人可以回答每一步都发生这种情况时内存中发生了什么吗?

JavaScript 规范没有定义内存中发生的事情。它定义了代码的外部行为。所以这将是一个实现细节,并且是特定于引擎的。

以下是执行代码时发生的情况的粗略介绍(在这两种情况下):

  1. 创建一个名为 a 的变量,并为其分配您在那里拥有的函数的值。
  2. 检查是否存在名为a 的变量。已经有一个了,所以什么都不做。
  3. 执行console.log并将a的值传递给它(就是那个函数)

【讨论】:

  • 有趣 - 感谢您的回复。我的理解是,在引擎逐步执行代码之前,在创建阶段没有分配任何值。这对于对象(当然包括函数对象)是错误的吗?另外,假设它们的名称不同,即 var a, function b(foo) { ...},这些是不同的内存位置不是吗?你是说只有一个内存位置,在这种情况下就是变量'b'。但是变量'a'呢?那么为什么我们在编译时没有得到引用错误,而是得到 undefined 呢?
  • @151SoBad 从广义上讲,您的 a/b 示例中将涉及三个内存位置:(1)a 变量所在的位置(2)b 变量所在的位置存在 (3) b 的值的位置。正如我上面所说的(用不太清楚的术语),您的初始示例中涉及两个内存位置:(1)a 变量本身的位置(2)a 值的位置(函数)。
  • 我完全同意并完全理解您在评论中所说的一切。我的问题也可能以不太明确的方式陈述。我知道只有一个变量 a,它位于内存中的一个位置。我的问题应该并且可以更好地提出:在执行上下文的创建阶段,当我们逐步执行代码时,该内存地址的值如何变化?
  • 通过扩展,在类似的注释中,您能否告诉我在 cmets 中的 a/b 示例中变量“a”的值是多少? (这实际上是我在另一个线程中的另一个问题,目前仍未得到解答,但您似乎对记忆有所了解,所以如果您知道,将不胜感激!)
  • @151SoBad 我认为您对 javascript 引擎的工作方式存在误解。线路没有“逐步执行”,也没有以某种方式重新排序线路的“提升”。有一个解析阶段会发现引入范围的变量,并且在执行代码时,范围被创建为一个 - 所有变量及其各自的初始值(undefined 用于 var,函数用于 function,或letconst 根本没有)。
【解决方案2】:

函数声明在变量提升之前被提升。

console.log(a);

var a = 42; // assignment

console.log(a);

function a(foo) { // a function named 'a'
  var foo = "Hello World";
  console.log(foo);
}

console.log(a);

【讨论】:

  • 我完全同意并且我理解当有一个任务正在发生时这是一个完全不同的场景。我只想知道,在没有发生赋值的情况下,为什么函数声明在变量提升之前被提升。是因为它是 ECMAScript 规范的实现而我们只是表面上接受它,还是我们可以解释这种行为?
  • @151SoBad 我只想知道,在没有发生赋值的情况下,为什么函数声明会在变量提升之前被提升。 因为规范就是这样定义行为的?除此之外,您还有什么需要了解的吗?
  • @JLRishe,不,这正是我想知道的。此外,我也找不到在规范中准确说明这一点的参考资料,因此我刚刚在 cmets 中提出了这个问题。就我所知,除了“规范”之外,规范的不同实现会保持不同的行为。我不太确定这里的态度暗示是什么。是的,我的问题可能与编码无关,也许在细节和琐碎方面,但肯定有人同样好奇(实际上可能不是,但我是在错误的网站上问这些问题吗? )。
  • @JLRishe 寻找我所知道的所有我可能正在接近如何错误地学习 Javascript 并接受表面上的东西,但在大多数情况下,我看到人们描述这种语言中的现象和特质这在逻辑上是有道理的(以及规范中也没有描述的没有意义的事情)。似乎有些人可能对实现及其工作原理有更好的理解,所以我很想看看是否存在这样的理解。我没有技术背景,所以我的提问可能会让人觉得不寻常,但它们是出于好意。
  • @151SoBad 查看规范的section 10.5。函数提升发生在该过程的第 5 步。变量提升发生在第 8 步。第 5 步在第 8 步之前,ergo 函数提升首先发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-27
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多