JavaScript 函数声明和求值顺序

2023-12-29

为什么这些示例中的第一个不起作用,但所有其他示例都起作用?

// 1 - does not work
(function() {
setTimeout(someFunction1, 10);
var someFunction1 = function() { alert('here1'); };
})();

// 2
(function() {
setTimeout(someFunction2, 10);
function someFunction2() { alert('here2'); }
})();

// 3
(function() {
setTimeout(function() { someFunction3(); }, 10);
var someFunction3 = function() { alert('here3'); };
})();

// 4
(function() {
setTimeout(function() { someFunction4(); }, 10);
function someFunction4() { alert('here4'); }
})();

这既不是范围问题,也不是封闭问题。问题在于理解之间声明 and 表达式.

JavaScript 代码,即使是 Netscape 的第一个 JavaScript 版本和 Microsoft 的第一个副本,也是分两个阶段处理的:

第 1 阶段:编译 - 在此阶段,代码被编译成语法树(以及字节码或二进制文件,具体取决于引擎)。

第 2 阶段:执行 - 然后解释解析后的代码。

函数的语法宣言 is:

function name (arguments) {code}

参数当然是可选的(代码也是可选的,但这有什么意义呢?)。

但 JavaScript 还允许您使用以下方式创建函数表达式。函数表达式的语法与函数声明类似,只是它们是在表达式上下文中编写的。表达式为:

  1. 右侧的任何内容=标志(或:关于对象字面量)。
  2. 括号内的任何内容().
  3. 函数的参数(这实际上已经在 2 中涵盖了)。

表达式 unlike 声明在执行阶段而不是编译阶段进行处理。正因为如此,表达式的顺序很重要。

所以,澄清一下:


// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();

第一阶段:编译。编译器看到变量someFunction被定义,所以它创建它。默认情况下,创建的所有变量的值都是未定义的。请注意,编译器此时还无法分配值,因为这些值可能需要解释器执行一些代码来返回要分配的值。在这个阶段我们还没有执行代码。

第二阶段:执行。解释器看到你想要传递变量someFunction设置超时。确实如此。不幸的是目前的价值someFunction未定义。


// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();

第一阶段:编译。编译器看到您正在声明一个名为 someFunction 的函数,因此它会创建它。

第 2 阶段:口译员发现您想要通过someFunction到setTimeout。确实如此。当前值someFunction是其编译后的函数声明。


// 3
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();

第一阶段:编译。编译器看到你已经声明了一个变量someFunction并创造它。和以前一样,它的值是未定义的。

第二阶段:执行。解释器将一个匿名函数传递给 setTimeout 以便稍后执行。在此函数中,它看到您正在使用变量someFunction所以它创建了变量的闭包。此时的值someFunction仍然是未定义的。然后它会看到你分配一个函数给someFunction。此时的值someFunction不再是未定义的。 1/100 秒后,setTimeout 触发并调用 someFunction。由于它的值不再是未定义的,因此它可以工作。


案例 4 实际上是案例 2 的另一个版本,其中加入了案例 3​​ 的一些内容。someFunction被传递给 setTimeout 它已经存在,因为它被声明了。


补充说明:

你可能想知道为什么setTimeout(someFunction, 10)不会在 someFunction 的本地副本和传递给 setTimeout 的副本之间创建闭包。答案是 JavaScript 中的函数参数始终是,always如果它们是数字或字符串,则按值传递;如果是其他内容,则按引用传递。因此 setTimeout 实际上并没有获取传递给它的变量 someFunction (这意味着要创建一个闭包),而只是获取 someFunction 引用的对象(在本例中是一个函数)。这是 JavaScript 中最广泛使用的机制,用于在发明之前打破闭包(例如在循环中)let关键词。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript 函数声明和求值顺序 的相关文章

随机推荐

  • 使用 ffmpeg 命令在视频中添加多个元数据

    添加单个元数据的命令工作正常 ffmpeg i var www html public uploads wp video akka mov metadata kKeyContentIdentifier com apple quicktime
  • 在 numpy 一维数组中查找拐点和驻点

    假设我有以下 numpy 数组 import numpy as np import matplotlib pyplot as plt x np array 11 53333333 11 86666667 11 1 10 66666667 1
  • 无法更改 unicode 字符的字体颜色

    确实很小的事情 但我在 Joomla 前端编辑页面的发布按钮上有这些日历图标 我为此使用 Unicode 字符 U 1F5D2 但我似乎无法使用 CSS 更改其颜色 我试图将其变成白色 浏览器检查员说它是白色的 但显然不是 请参阅此处的示例
  • 在 ARMv8-A Linux 上禁用 CPU 缓存 (L1/L2)

    我想在运行 Linux 的 ARMv8 A 平台上禁用低级缓存 以便独立于缓存访问来测量优化代码的性能 对于英特尔系统 我找到了以下资源 有没有办法在 Linux 系统上禁用 CPU 缓存 L1 L2 https stackoverflow
  • TensorFlow - Saver.restore 未恢复所有参数

    我训练了双向 LSTM 类型的 RNN 近 24 小时 由于误差波动 我决定在允许其继续训练之前减少学习量 由于模型在每个时期都使用 Saver save sess file 保存 因此我终止了训练 CTC 损失已最小化至大约 115 现在
  • 使用 gruntjs 组合并缩小所有 Bower 库

    有没有办法自动将所有 Bower 安装的库合并并缩小为 1 个文件 首先我尝试了最基本的方法 将所有 js所有子目录中的文件 uglify options compress true my target files vendor js bo
  • 如何禁用 libsvm (java) 中的控制台输出

    我正在使用 libsvmjava并且遇到了与描述类似的问题here https stackoverflow com questions 8302519 suppressing the output in libsvm python对于蟒蛇
  • 如何捕获java.sql.SQLIntegrityConstraintViolationException?

    我的应用程序使用 JPA JavaDB 当我尝试保留违反约束的对象时 我得到SQLIntegrityConstraintViolationException http docs oracle com javase 7 docs api ja
  • 为什么 Mongoose 不验证更新?

    我有这个代码 var ClientSchema new Schema name type String required true trim true var Client mongoose model Client ClientSchem
  • 导航控制器栏被切断

    如果通过选择隐藏状态栏status bar style hide during application launch我正在自定义导航栏 如下所示 UINavigationBar appearance setBackgroundImage U
  • 以日历日为单位分割间隔的持续时间

    我有以下数据集 显示一集的开始和结束 日期和时间 ep lt data frame start c 2009 07 13 23 45 00 2009 08 14 08 30 00 2009 09 16 15 30 00 end c 2009
  • “POSIX”是什么意思?

    什么是 POSIX 我已阅读维基百科文章 http en wikipedia org wiki POSIX每次遇到这个词我都会读它 事实是我从来没有真正理解它是什么 任何人都可以通过解释 POSIX 的需要 来向我解释一下吗 POSIX h
  • 尝试混合属于不同事务的对象

    pony orm core TransactionError An attempt to mix objects belonging to different transactions 我知道这个错误是描述性的 我只是不明白为什么会发生 我
  • HikariCP 连接过多

    我有一个Java Servlet 我想将连接池与jdbc 数据库 mysql 一起使用 所以这就是我正在做的 这个类是公共最终类DBConnector private static final HikariDataSource dataSo
  • 如何仅为一个 Razor 页面设置 `ValidationVisitor.MaxValidationDepth` = 1?

    我该如何改变ValidationVisitor MaxValidationDepth在本地为一个 Razor 页面阻止验证子对象 我不想在全球范围内改变它MvcOptions MaxValidationDepth就像文档中描述的那样 最大递
  • 如何在默认 Spring Data JPA 方法上添加 QueryHints?

    我可以将查询缓存与 Spring Data JPA 一起用于我的自定义查询方法 如下所示 public interface CountryRepository extends JpaRepository
  • Spring Singleton 范围与应用程序范围

    单例和应用程序弹簧范围有什么区别 我知道单例作用域为每个应用程序创建一个实例 并且应用程序作用域以相同的方式工作 那么主要区别是什么 我需要一个例子来展示其中的区别 要了解应用程序范围和单例范围之间的区别 您需要了解 ServletCont
  • Spring - 在浏览器中显示 PDF 文件而不是下载

    我正在尝试使用 spring 在浏览器中显示 pdf 我的问题是浏览器下载文件而不是显示它 这是我的代码 RequestMapping value getpdf1 method RequestMethod GET public Respon
  • 将自定义声明添加到 azure b2c 客户端凭据流

    我已将 b2c 配置为客户端凭据流的授权服务器 我想向令牌添加声明 以便我可以使用策略将其发送到 APIM 中的后端服务 但我找不到一种方法来将这个额外的声明添加到令牌中 以便我可以在 APIM 上使用它 注意 可以使用授权代码流 但使用客
  • JavaScript 函数声明和求值顺序

    为什么这些示例中的第一个不起作用 但所有其他示例都起作用 1 does not work function setTimeout someFunction1 10 var someFunction1 function alert here1