JavaScript:理解闭包和提升

标签 javascript closures hoisting

我知道函数声明被提升到其作用域的顶部。这允许我们在 JavaScript 中实际声明之前使用这些函数:

sayHello(); // It works!

function sayHello() {
  console.log('Hello');
}

我还了解到闭包使函数能够保留对在同一范围内声明的变量的引用:

function outerFxn() {
  let num = 0;

  function innerFxn() {
    console.log(num);
    num++;
  }

  return innerFxn;
}

const logNum = outerFxn();
logNum(); // 0
logNum(); // 1
logNum(); // 2

到目前为止一切顺利。但这里有一些奇怪的地方,我希望有人能准确解释发生了什么......

场景一:可理解的闭包

function zero(cb) {
  return setTimeout(cb, 0);
}

function test1() {
  let txt = 'this is a test message';

  function log() {
    console.log(txt);
  }

  zero(log);
}

在上面的示例中,log 函数保留对其创建范围的引用,保存在 txt 变量中。然后,当稍后在 setTimeout 中执行时,它成功记录了 txt 变量的值。伟大的。然后就是这个...

场景 2:发生了什么?

function zero(cb) {
  return setTimeout(cb, 0);
}

function test1() {
  function log() {
    console.log(txt);
  }

  let txt = 'this is a test message';

  zero(log);
}

我已将 log 函数声明移动到范围的顶部(无论如何它都会被提升到那里,对吧?),然后我正在声明txt 变量在它下面。这一切仍然有效,我不确定为什么。当 letconst 未提升时,log 如何保留对 txt 变量的引用向上?是否对闭包作用域作为一个整体进行了分析?我可以在这里逐步说明 JavaScript 引擎正在做什么。谢谢你!

最佳答案

它是您离开 test1 函数后作用域的一部分。此时它是否与 varletconst 一起使用并不重要。由于对整个 body 进行了评估,因此该变量存在于范围内。

如果您在评估 let 声明之前尝试使用 log,则会收到错误。

编辑:从技术上讲,用 letconst 声明的变量在范围内,但它们被单元化,如果您尝试访问它们。只有在您到达声明时它们才会被初始化并且您可以访问它们。所以它们总是在范围内,只是在评估声明之前不可用。

关于JavaScript:理解闭包和提升,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45461858/

相关文章:

javascript - Github 说我在 package-lock (cryptiles) 中有一个 Node 安全漏洞,但它没有安装在 package.json 中,我没有使用它,解决方案?

c# - 可以在闭包中 Lock() 吗?这在 Lambda 和代码输出中是什么样子的?

javascript - 如何取消修补 Javascript 对象中的方法?具体来说是 XMLHttpRequest.open

python - Python 闭包中有什么?对于习惯 OCaml 的人来说有哪些注意事项?

javascript - 为什么回调函数没有在 JavaScript 中提升?

javascript - 功能被提升。 fun1 调用 fun2。他们以什么顺序声明?

javascript - ngSanitize 仍然显示文本而不是 HTML

javascript - 本地镜像的 getImageData 错误

javascript - DOM "style"属性和实际 CSS 样式之间的关系

javascript - 提升没有声明为 'var' 的 JS 变量