JavaScript 中的函数顺序

发布于 2024-10-08 19:20:58 字数 523 浏览 7 评论 0原文

我的问题基于“面向对象的 JavaScript”一书中的示例(第 81 页 - 词汇范围)

所以,我从这个例子中了解到……

function f1(){var a = 1; f2();}
function f2(){return a;}
f1();

a 未定义

但是,f1 如何了解在 f1 之后定义的 f2 呢?

这种行为提出了一个问题:

JavaScript 解释器如何工作?

我假设它:

  1. 扫描代码并简单地将函数存储在全局环境中,而不是分配给任何变量
  2. 以临时方式调用函数:当全局环境中没有这样的函数时,则抱怨。

My question is based on the example from a book "Object Oriented JavaScript" (page 81 - Lexical Scope)

So, i understand from this example ...

function f1(){var a = 1; f2();}
function f2(){return a;}
f1();

... that:

a is not defined

But, how f1 get's to know about f2, which is defined after f1 ?

This behavior raises a question:

How JavaScript interpreter works ?

I assume, that it:

  1. scans the code and simply stores the functions, not assigned to any var, in a global environment
  2. Invokes a function in ad-hoc way: when there is no such a function in a global environment, then complain.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白馒头 2024-10-15 19:20:58

函数声明在进入可执行上下文(例如,全局上下文或函数调用)时进行处理,然后再处理上下文中的任何分步代码。

因此,在您的代码中,会发生以下事情(按此顺序):

  1. 为执行上下文创建“变量对象”。
  2. “变量对象”上的条目(实际上是字面上的属性)是为上下文中的每个 var 和函数声明(加上一些其他内容)创建的。在您的例子中,即 f1f2。最初,这些属性的值为未定义
  3. 所有函数声明都已处理,因此:
    • f1 函数已定义并分配给变量对象的属性。
    • 定义 f2 函数并将其分配给变量对象的属性。
  4. 执行 f1(); 行,调用 f1 函数。
  5. f1 代码引用 f2,它是从变量对象中获取的,因此它就是我们所期望的(对 f2 的引用) > 功能)。

更有趣的版本是这样的:

f1();
function f1(){var a = 1; f2();}
function f2(){return a;}

...它的发生顺序与上面列出的顺序完全相同,因为这两个声明都是在第一行分步代码之前处理的。

函数声明与函数表达式不同,函数表达式就像任何其他表达式一样,在代码的逐步执行中到达时对其进行求值。函数表达式是指您创建函数并将其用作右手值的任何时间,例如,将结果分配给变量或将其传递给另一个函数。像这样:

var f2 = function() {
};

或这样

setTimeout(function() {
    alert("Hi there");
}, 1000);

请注意,我们使用 function 语句的结果作为右侧值(在赋值中,或将其传递到函数中)。这些不会在进入执行上下文时进行预处理(例如,不在上面的步骤3),而是在代码流到达它们时进行处理。这会导致:

f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};

...失败,因为 f2 在调用时尚未定义。

您可以将声明的函数的值用作右侧值,而无需将其转换为函数表达式(我们一直这样做),只要您在两个单独的语句中执行此操作即可。所以:

alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);

按以下顺序发生:

  1. 创建 foo (因为它是由声明定义的)。
  2. 警报运行。
  3. setTimeout 运行。
  4. (稍后)foo 被调用。

最后一点:虽然它们应该工作,但包含函数名称的函数表达式不能在所有实现上可靠地工作,目前必须避免:

var f = function foo() { ... }; // <== DON'T DO THIS

或者

setTimeout(function foo() {     // <== DON'T DO THIS
}, 1000);

Internet Explorer特别是,这些方面存在问题,其他实现在不同时间也存在问题。

更多探索:

Function declarations are processed upon entry into an executable context (e.g., the global context, or a function call), prior to any of the step-by-step code in the context being processed.

So in your code, these things happen (in this order):

  1. A "variable object" is created for the execution context.
  2. Entries (actually, literally, properties) on the "variable object" are created for every var and function declaration in the context (plus a few other things). In your case, that's f1 and f2. Initially the properties have the value undefined.
  3. All function declarations are processed, and so:
    • The f1 function is defined and assigned to its property on the variable object.
    • The f2 function is defined and assigned to its property on the variable object.
  4. The f1(); line is executed, calling the f1 function.
  5. The f1 code refers to f2, which it gets from the variable object, and so it's what we expect it to be (a reference to the f2 function).

The more interesting version is this:

f1();
function f1(){var a = 1; f2();}
function f2(){return a;}

...which happens in exactly the same order listed above, because both of the declarations are handled before the first line of step-by-step code.

Function declarations are different from function expressions, which just like any other expression are evaluated when they're reached in the step-by-step execution of the code. A function expression is any time you create a function and use it as a right-hand value, e.g., assign the result to a variable or pass it into another function. Like this:

var f2 = function() {
};

or this

setTimeout(function() {
    alert("Hi there");
}, 1000);

Note that we're using the result of the function statement as the right-hand value (in an assignment, or by passing it into a function). Those are not pre-processed upon entry into an execution context (e.g., not at Step 3 above), they're handled when the flow of code reaches them. Which leads to:

f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};

...which fails, because f2 is undefined as of when it's called.

You can use a declared function's value as a right-hand value without turning it into a function expression (we do that all the time), so long as you do it in two separate statements. So:

alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);

That happens in this order:

  1. foo is created (since it's defined by a declaration).
  2. The alert runs.
  3. The setTimeout runs.
  4. (Later) foo is called.

One last point: Although they should work, a function expression that includes a function name does not work reliably on all implementations and must, for now, be avoided:

var f = function foo() { ... }; // <== DON'T DO THIS

Or

setTimeout(function foo() {     // <== DON'T DO THIS
}, 1000);

Internet Explorer, in particular, has issues with those, and other implementations have at various times as well.

More to explore:

药祭#氼 2024-10-15 19:20:58

您无权访问函数 f1 内的变量“a”,因为

如果您在 f1 内定义 f2,则函数 f2 未在 f1 范围内定义:

function f1(){function f2(){return a;} var a = 1; f2();}
f1();

您没有任何问题

you don't have access to variable 'a' inside function f1, because function f2 is not defined inside f1 scope

if you define f2 inside f1:

function f1(){function f2(){return a;} var a = 1; f2();}
f1();

you don't have any problems

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文