为什么 JavaScript 不需要 main() 函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9015836/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 08:24:26  来源:igfitidea点击:

Why doesn't JavaScript need a main() function?

javascript

提问by micpalmia

Many programming languages require a special user-written function that marks the begin of the execution. For example, in C this function must always have the name main(). In JavaScript, however, such a function is not required.

许多编程语言需要一个特殊的用户编写的函数来标记执行的开始。例如,在 C 中,此函数必须始终具有名称main()。但是,在 JavaScript 中,不需要这样的函数。

What are the logical reason for the absence of such a dedicated top level function in JavaScript? I know this is some kind of theoretical question, but I cannot find an answer online.

JavaScript 中缺少这种专用的顶级函数的逻辑原因是什么?我知道这是某种理论问题,但我无法在网上找到答案。

回答by T.J. Crowder

Because the entire code block is effectively one big main. In JavaScript, global code can have all of the constructs function code can have, and has stepwise execution, just like functions do. In fact, when the JS engine processes the code block as a whole, it does very nearly the same things that it does when processing a function call. See the specification's sections 10.4.1("Entering Global Code") and 10.4.3("Entering Function Code") and note how similar they are.

因为整个代码块实际上是一大块main。在 JavaScript 中,全局代码可以具有函数代码可以具有的所有构造,并且可以逐步执行,就像函数一样。事实上,当 JS 引擎作为一个整体处理代码块时,它所做的事情与处理函数调用时所做的事情非常相似。请参阅规范的第10.4.1节(“输入全局代码”)和10.4.3(“输入功能代码”)并注意它们的相似程度。

C doesn't allow stepwise code at the global level (you can have all sorts of initializers, and they can get kind of stepwise, but that's a different topic). And so C needs an explicit entry point (main). In JavaScript, the entry point is the beginning of the code.

C 不允许全局级别的逐步代码(您可以拥有各种初始化程序,它们可以逐步进行,但这是一个不同的主题)。所以 C 需要一个显式的入口点 ( main)。在 JavaScript 中,入口点是代码的开头。



Regarding your question below about whether global code is sequential. The answer is yes, it's exactly like code in a function that way. So:

关于您在下面关于全局代码是否是顺序的问题。答案是肯定的,它就像函数中的代码那样。所以:

var x, y, z;
x = 1;
y = 2;
z = x + y;
alert("z is " + z);

...will alert "z is 3". The code runs sequentially, top to bottom.

...会提醒"z is 3"。代码按顺序运行,从上到下。

There are a couple of things that happen beforethe stepwise code is executed, though, which is useful to know. The most significant is that any declarationsin the source text of the scope being entered are processed before the stepwise code begins. JavaScript has two main types of declarations: Variable declarations, and function declarations:

但是,在执行逐步代码之前会发生一些事情,这很有用。最重要的是,输入范围的源文本中的任何声明都在逐步代码开始之前处理。JavaScript 有两种主要类型的声明:变量声明和函数声明:

  1. The name of any variable declared with varis added to the scope (with the value undefined) before any stepwise code is executed. (More: Poor, misunderstood var)

  2. Function declarationsare processed and the function names added to the scope before any stepwise code is executed. (JavaScript also has something else, called a function expression, which is stepwise code. More on that below.)

  1. 在执行任何逐步代码之前var,将使用声明的任何变量的名称添加到作用域(带有值undefined)。(更多:可怜,被误解var

  2. 在执行任何逐步代码之前,处理函数声明并将函数名称添加到作用域中。(JavaScript 也有其他东西,称为函数表达式,它是逐步代码。更多内容见下文。)

So for instance, in this source text:

例如,在这个源文本中:

var x;
x = 1;
foo();

function foo() {
}

the declarations are

声明是

var x;
function foo() {
}

and the stepwise code is

和逐步代码是

x = 1;
foo();

The declarations are processed first. This is why the call to fooworks. (These same rules apply to the source text within functions.) This processing of declarations before anything else is sometimes called "hoisting," because the declarations are in a sense lifted from their location in the source text and moved to the very beginning. I prefer to think of it as two passes through the source: The first pass does declarations, the second executes stepwise code.

首先处理声明。这就是调用 的原因foo。(这些相同的规则适用于函数内的源文本。)这种在其他任何事情之前的声明处理有时称为“提升”,因为在某种意义上,声明是从它们在源文本中的位置提升并移到最开始的。我更愿意将其视为两次通过源代码:第一次执行声明,第二次执行逐步代码。

(Side note: Declaring a variable more than once in the same scope is perfectly legal [though pointless]. Declaring two functions with the same name is also legal; the latter declaration overrides the earlier one.)

(旁注:在同一个范围内多次声明一个变量是完全合法的[虽然毫无意义]。声明两个同名的函数也是合法的;后一个声明覆盖了前一个。)

(Side note 2: ES2015 [ES6] introduced letand constvariable declarations, which behave somewhat differently from var. You can't declare a variable twice with them, they have block scope, and you can't use the variable prior to the statement where it's declared. So they're mostly not hoisted [there is something slightlylike hoisting in that they prevent access to a shadowed variable in a containing scope even before the let xor whatever line].)

(附注2:ES2015 [ES6]介绍letconst变量声明,这在某种程度上表现为不同的var,你不能与他们一个变量声明两次,他们有块范围,它是你不能使用该语句的变量之前声明。所以它们大多没有被提升 [有点类似于提升,因为它们甚至在let x或任何行之前阻止访问包含范围中的阴影变量]。)



More detail, and possibly getting a bit technical:

更多细节,可能会有点技术性:

var

var

If varhappens before the stepwise code is run, you may be wondering about this:

如果var在逐步代码运行之前发生,您可能想知道这一点:

var x = 1;

Does that happen before stepwise code, or as part of it? The answer is that in reality, that's just shorthand for two very different things:

这是在逐步代码之前发生还是作为它的一部分发生?答案是,实际上,这只是两种截然不同的事物的简写:

var x;
x = 1;

The var x;part happens before the stepwise code, the x = 1;part is stepwise code and is executed when we reach it in the sequence. So:

var x;部分发生在逐步代码之前,该x = 1;部分是逐步代码,并在我们按顺序到达时执行。所以:

alert(x); // "undefined" -- there **is** a variable `x`; it has the value `undefined`
var x = 1;
alert(x); // "1" -- now `x` has the value `1`

Function declarations

函数声明

JavaScript has two different, but very similar-looking, things: Function declarations, and function expressions. You can tell which is which by whether you're using the resulting function as part of the expression in which it's defined.

JavaScript 有两个不同但非常相似的东西:函数声明和函数表达式。您可以通过是否将结果函数用作定义它的表达式的一部分来判断哪个是哪个。

Here's a function declaration:

这是一个函数声明

function foo() {
}

These are all function expressions(we use the resulting function value as part of the expression; in computer science terminology, the function is used as a right-hand value):

这些都是函数表达式(我们使用结果函数值作为表达式的一部分;在计算机科学术语中,函数用作右手值):

// 1: Assigning the result to something
var x = function() {
};

// 2: Passing the result into a function
bar(function() {
});

// 3: Calling the function immediately
(function(){
})();

// 4: Also calling the function immediately (parens at end are different)
(function(){
}());

// 5: Also calling the function immediately
!function(){
}();

// 6: Syntax error, the parser needs *something* (parens, an operator like ! or
// + or -, whatever) to know that the `function` keyword is starting an *expression*,
// because otherwise it starts a *declaration* and the parens at the end don't make
// any sense (and function declarations are required to have names).
function(){
}();

The rule is that function declarations are processed before the stepwise code begins. Function expressions, like all other expressions, are processed where they're encountered.

规则是在逐步代码开始之前处理函数声明。函数表达式与所有其他表达式一样,在遇到它们的地方进行处理。

One final side note: This is a namedfunction expression:

最后一个旁注:这是一个命名函数表达式

var f = function foo() {
};

We use it as a right-hand value, so we know it's an expression; but it has a name like function declarations do. This is perfectly valid and legal JavaScript, and what it's meant to do is create a function with a proper name (foo) as part of the stepwise code. The name of the function is notadded to the scope (as it would be if it were a function declaration).

我们将它用作右手边的值,所以我们知道它是一个表达式;但它有一个像函数声明那样的名字。这是完全有效且合法的 JavaScript,它的目的是创建一个具有适当名称 ( foo)的函数作为逐步代码的一部分。函数的名称不会添加到作用域中(就像它是函数声明一样)。

However, you won't see named function expressions in very many places, because JScript (Microsoft's JavaScript engine) gets them horribly and utterly wrong, creating two separate functions at two different times.

但是,您不会在很多地方看到命名函数表达式,因为 JScript(Microsoft 的 JavaScript 引擎)将它们弄得非常可怕且完全错误,在两个不同的时间创建了两个单独的函数。

回答by Dan D.

in a scripting language, the code is executed from the first line in the file to the end as if it was being typed into an interpreter. (this doesn't preclude parsing and compiling the code as long as those process don't effect the denotational semantics described.)

在脚本语言中,代码从文件的第一行到最后执行,就好像它被输入到解释器中一样。(这并不排除解析和编译代码,只要这些过程不影响所描述的指称语义。)

回答by Tomasz Nurkiewicz

JavaScript is event-driven, the program written in JavaScript doesn't have a start and an end. You can compare it to any desktop UI toolkit, where you handle button clicks and key presses, but there is no obvious mainonce the program is initialized.

JavaScript 是事件驱动的,用 JavaScript 编写的程序没有开始和结束。您可以将其与任何桌面 UI 工具包进行比较,您可以在其中处理按钮点击和按键操作,但是main一旦程序初始化就没有明显的效果。

For instance there is a window.onloadevent that is triggered when the page is loaded - and which you can handle.

例如window.onload,在加载页面时会触发一个事件 - 您可以处理该事件。

回答by CAGE

You already know the answer

你已经知道答案了

In JavaScript, however, such a function is not required!

然而,在 JavaScript 中,这样的函数不是必需的!

JavaScript is scripting language while C needs to be compiled.

JavaScript 是脚本语言,而 C 需要编译。