JavaScript函数声明和评估顺序 [英] JavaScript function declaration and evaluation order

查看:165
本文介绍了JavaScript函数声明和评估顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Why does the first one of these examples not work, but all the other ones do?

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


推荐答案

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

This is neither a scope problem nor is it a closure problem. The problem is in understanding between declarations and expressions.

JavaScript代码,因为即使是Netscape的第一个版本的JavaScript和微软的第一个副本分两个阶段处理:

JavaScript code, since even Netscape's first version of JavaScript and Microsoft's first copy of it, is processed in two phases:

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

Phase 1: compilation - in this phase the code is compiled into a syntax tree (and bytecode or binary depending on the engine).

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

Phase 2: execution - the parsed code is then interpreted.

函数的语法声明是:

function name (arguments) {code}

参数当然是可选的(代码也是可选的,但重点是什么?)。

Arguments are of course optional (code is optional as well but what's the point of that?).

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

But JavaScript also allows you to create functions using expressions. The syntax for function expressions are similar to function declarations except that they are written in expression context. And expressions are:


  1. = 符号右侧的任何内容(或 on object literals)。

  2. 括号中的任何内容()

  3. 函数的参数(这实际上已经被2覆盖)。

  1. Anything to the right of an = sign (or : on object literals).
  2. Anything in parentheses ().
  3. Parameters to functions (this is actually already covered by 2).

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

Expressions unlike declarations are processed in the execution phase rather than the compilation phase. And because of this the order of expressions matter.

因此,澄清:

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

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

Phase 1: compilation. The compiler sees that the variable someFunction is defined so it creates it. By default all variables created have the value of undefined. Note that the compiler cannot assign values yet at this point because the values may need the interpreter to execute some code to return a value to assign. And at this stage we are not yet executing code.

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

Phase 2: execution. The interpreter sees you want to pass the variable someFunction to setTimeout. And so it does. Unfortunately the current value of someFunction is undefined.

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

阶段1:编译。编译器看到你声明了一个名为someFunction的函数,因此它创建了它。

Phase 1: compilation. The compiler sees you are declaring a function with the name someFunction and so it creates it.

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

Phase 2: The interpreter sees you want to pass someFunction to the setTimeout. And so it does. The current value of someFunction is its compiled function declaration.

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

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

Phase 1: compilation. The compiler sees you have declared a variable someFunction and creates it. As before, its value is undefined.

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

Phase 2: execution. The interpreter passes an anonymous function to setTimeout to be executed later. In this function it sees you're using the variable someFunction so it creates a closure to the variable. At this point the value of someFunction is still undefined. Then it sees you assigning a function to someFunction. At this point the value of someFunction is no longer undefined. 1/100th of a second later the setTimeout triggers and the someFunction is called. Since its value is no longer undefined it works.

案例4实际上是案例2的另一个版本,有点像案例抛出3点。在 someFunction 点传递给setTimeout它因为被声明而已经存在。

Case 4 is really another version of case 2 with a bit of case 3 thrown in. At the point someFunction is passed to setTimeout it already exists due to it being declared.

补充说明:

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

You may wonder why setTimeout(someFunction, 10) doesn't create a closure between the local copy of someFunction and the one passed to setTimeout. The answer to that is that function arguments in JavaScript are always, always passed by value if they are numbers or strings or by reference for everything else. So setTimeout does not actually get the variable someFunction passed to it (which would have meant a closure being created) but rather only gets the object that someFunction refers to (which in this case is a function). This is the most widely used mechanism in JavaScript for breaking closures (for example in loops).

这篇关于JavaScript函数声明和评估顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆