当前位置: 首页 > 面试题库 >

JavaScript函数声明和评估顺序

鞠建安
2023-03-14
问题内容

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

// 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'); }
})();

问题答案:

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

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

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

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

函数 声明 的语法为:

function name (arguments) {code}

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

但是JavaScript也允许您使用 表达式 创建函数。函数表达式的语法与函数声明相似,区别在于它们是在表达式上下文中编写的。表达式为:

  1. =标志右边(或:对象文字上)的任何内容。
  2. 括号中的任何内容()
  3. 函数的参数(实际上已经被2覆盖了)。

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

因此,澄清一下:

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

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

阶段2:执行。解释器看到您要将变量传递someFunction给setTimeout。确实如此。不幸的是的当前值someFunction是不确定的。

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

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

阶段2:解释器看到您要传递someFunction给setTimeout。确实如此。的当前值someFunction是其编译的函数声明。

// 3
(function() {
setTimeout(functhtml" target="_blank">ion() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();

阶段1:编译。编译器会看到您已经声明了一个变量someFunction并创建了它。和以前一样,它的值是不确定的。

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

情况4实际上是情况2的另一个版本,其中包含了情况3 someFunction

附加说明:

您可能想知道为什么setTimeout(someFunction, 10)在someFunction的本地副本和传递给setTimeout的本地副本之间不创建闭包。答案是,JavaScript中的函数参数 始终
是数值(如果是数字或字符串)或其他所有引用都按值传递。因此,setTimeout实际上并不会获取传递给它的变量some​​Function(这将意味着正在创建一个闭包),而只会获取someFunction所引用的对象(在这种情况下为函数)。这是JavaScript中打破闭合(例如在循环中)使用最广泛的机制。



 类似资料:
  • 问题内容: 可以安全地假设函数参数在Python中是从左到右求值的吗? 参考文献指出,这种情况会发生,但是也许有某种方法可以更改此顺序,这可能会破坏我的代码。 我想做的是为函数调用添加时间戳: 我知道我可以按顺序评估参数: 但是它看起来不太优雅,因此如果可以依靠它,我宁愿采用第一种方法。 问题答案: 是的,Python始终从左到右评估函数参数。 据我所知,这适用于任何逗号分隔的列表:

  • 问题内容: 有人可以解释一下SELECT语句的概念执行顺序是什么,请提供一个示例吗? 我在Google上进行了搜索,但它们似乎都使用了相同的示例,而没有详尽的解释。 问题答案: 从概念上讲,按以下顺序评估查询: 该条款 该条款 该条款 该条款 该条款 该条款 这是“概念性”处理,解释了SQL的一些作用域规则。实际上,查询的执行方式可能有所不同。 SQL Server文档在此处说明了此顺序。

  • 5.1. 函数声明 函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。 func name(parameter-list) (result-list) { body } 形式参数列表描述了函数的参数名以及参数类型。这些参数作为局部变量,其值由参数调用者提供。返回值列表描述了函数返回值的变量名以及类型。如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的。如

  • 本文向大家介绍javascript函数声明和函数表达式区别分析,包括了javascript函数声明和函数表达式区别分析的使用技巧和注意事项,需要的朋友参考一下   平时再用js写函数的时候,一般都是以惯例 function fn () {} 的方式来声明一个函数,在阅读一些优秀插件的时候又不免见到 var fn = function () {} 这种函数的创建,究竟他们用起来有什么区别呢,今天就本

  • 本文向大家介绍举例子说明javascript的变量声明提升和函数声明提升相关面试题,主要包含被问及举例子说明javascript的变量声明提升和函数声明提升时的应答技巧和注意事项,需要的朋友参考一下 先声明函数名,再声明 var 变量名,然后按顺序从上到下赋值。

  • 问题内容: 以下Python表达式之间有什么区别: 第一给出的结果与第二给出的结果不同。 例如, 第一: 第二: y是第一的 3 和第二的 4 问题答案: 在赋值语句中,总是在对变量进行实际设置之前先对右侧进行全面评估。所以, 评估板y(我们称之为的结果),评估(呼叫),然后设置要和y到。也就是说,就像 相比之下, 设置x为y,然后设置,因此等效于