【问题标题】:function hoisting for inner function calls [duplicate]内部函数调用的函数提升[重复]
【发布时间】:2021-12-24 03:06:11
【问题描述】:

请注意:^ 此问题与 let/const 问题不重复,因为这无关。无论是varlet 还是const,都会保留相同的问题,因为这与问题的意图无关。


非常感谢您对另一个函数中的函数提升进行一些澄清。这是我目前清楚明白的:

这不起作用,因为anotherFunc 在创建之前在文件中被调用,而const 在创建之前没有提升。

const someFunc = () => {
 console.log('someFunc called');
}
   
anotherFunc(); // anotherFunc is not defined error
   
const anotherFunc = () => {
 console.log('anotherFunc called');
}

这是可行的,因为anotherFunc 是一个函数声明,它们根据 JS 规则被提升到顶部:

anotherFunc(); // anotherFunc called

function anotherFunc() {
    console.log('anotherFunc called');
}

不起作用,因为它是一个函数表达式,并且由于它们被分配给var 变量,因此该变量将被提升到顶部并且最初是未定义的:

anotherFunc(); // anotherFunc is not a function at <anonymous>

var anotherFunc = function () {
    console.log('anotherFunc called');
}

那么有人可以向我解释为什么这样做(见下文)吗?这比在线解释的所有内容更深入。

如果一个函数稍后声明,但在它之前的另一个函数中被调用,为什么它会起作用?这跟JS执行顺序有关系吗?

const someFunc = () => {
    console.log('someFunc called');
    anotherFunc();
}
   
const anotherFunc = () => {
 console.log('anotherFunc called');
}

someFunc(); // 'someFunc called' 'anotherFunc called'

是不是因为someFuncanotherFunc是JS先在内存中分配的,所以以后调用它们不管它们的顺序是什么?

最后,同一个场景(最后一个)中的 const/let/var 函数有区别吗?

非常感谢您的澄清!

【问题讨论】:

  • 重要的是你在定义函数之后调用它。源代码中的顺序无关紧要,只是时间。
  • 由于在定义了两个函数之后调用someFunc,所以someFunc可以调用anotherFunc
  • 谢谢巴尔玛!但我想知道的更深一点。就像 JavaScript 中到底发生了什么?为什么someFunc 定义后可以调用anotherFunc? JS 是否首先将它们存储在内存中,然后当anotherFunc 被调用时,它只是获得了一个已经在该内存中可用的函数?要不然是啥?事件的顺序是什么,这才是我真正好奇的。
  • function foo() { console.log(variable); } let variable = "bar"; foo();
  • 重要的一点是,JavaScript 不需要在函数定义中引用它们之前声明名称。仅在引用它们的代码执行之前。

标签: javascript scope executioncontext


【解决方案1】:

JavaScript 的执行上下文有两个组件:

  • 内存(可变环境)
  • 代码(执行线程) - 同步和单线程意味着 JS 只能以一定的顺序(一个接一个)一个接一个地做事

所以这是有效的原因:

const someFunc = () => {
    console.log('someFunc called');
    anotherFunc();
}
   
const anotherFunc = () => {
 console.log('anotherFunc called');
}

someFunc(); // 'someFunc called' 'anotherFunc called'

...是因为 JS 首先在内存中将someFuncanotherFunc 分配给undefined(正如我在问题中所怀疑的那样)。函数声明也作为整个函数保存在这里。

这是内存分配阶段。 然后它运行代码执行阶段。

JS 逐行添加变量的值。

如果保存在内存中的键的值是一个函数,它会创建另一个内部执行上下文,并再次为该特定函数运行内存分配和代码执行阶段。

所以在我的情况下:

  1. 创建执行上下文。
  2. someFuncanotherFunc 分配到内存为 undefined
  3. someFunc 被调用并创建一个新的内部执行上下文。
  4. console.log 运行。
  5. anotherFunc 被保存到 undefined 内存中的 someFunc 执行上下文中。代码执行运行并调用anotherFunc,并为该函数创建另一个执行上下文。由于它没有变量等,它只运行console.log
  6. anotherFunc 已完成,其执行上下文被删除。它将自己的权力交还给someFunc(当函数返回时也会发生这种情况)。
  7. someFunc 已完成,它的执行上下文被删除。它将其权力交还给主 JS 执行上下文。(当函数返回时也会发生这种情况)。

这家伙解释的很清楚:https://youtu.be/iLWTnMzWtj4

【讨论】:

  • constletclass 在创建时未使用 undefined 进行初始化,它们未初始化。
  • 是的,你是对的。 constlet 仍然被提升并在内存中创建,但在代码运行之前它们不会被初始化。这称为“时间死区”。这就是为什么如果在声明它们之前调用它们会出现引用错误。
  • 虽然我不知道class。真的吗? JS 本身没有类,它们只是下面的函数,所以我想知道为什么它们没有被提升,至少类似于函数表达式,即自动设置为 undefined
  • 好的,谢谢! :)
猜你喜欢
  • 2016-10-07
  • 2017-08-07
  • 1970-01-01
  • 2013-06-27
  • 2013-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
相关资源
最近更新 更多