简体   繁体   English

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

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

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() . 例如,在C中,此函数必须始终具有名称main() In JavaScript, however, such a function is not required. 但是,在JavaScript中,不需要此功能。

What are the logical reason for the absence of such a dedicated top level function in JavaScript? 在JavaScript中缺少如此专用的顶级功能的逻辑原因是什么? I know this is some kind of theoretical question, but I cannot find an answer online. 我知道这是某种理论上的问题,但是我无法在线找到答案。

Because the entire code block is effectively one big main . 因为整个代码块实际上是一大main In JavaScript, global code can have all of the constructs function code can have, and has stepwise execution, just like functions do. 在JavaScript中,就像函数一样,全局代码可以具有函数代码可以具有的所有构造,并且可以逐步执行。 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. 实际上,当JS引擎整体上处理代码块时,它执行的功能与处理函数调用时几乎相同。 See the specification's sections 10.4.1 ("Entering Global Code") and 10.4.3 ("Entering Function Code") and note how similar they are. 请参阅规范的第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). C不允许在全局级别上使用逐步代码(您可以使用各种初始化程序,并且它们可以进行某种逐步操作,但这是不同的主题)。 And so C needs an explicit entry point ( main ). 因此,C需要一个显式的入口点( main )。 In JavaScript, the entry point is the beginning of the code. 在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" . ...将警告"z is 3" The code runs sequentially, top to bottom. 该代码从上到下依次运行。

There are a couple of things that happen before the stepwise code is executed, though, which is useful to know. 但是,在执行逐步代码之前 ,会发生一些事情,这对您很有用。 The most significant is that any declarations in 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 var is added to the scope (with the value undefined ) before any stepwise code is executed. 在执行任何逐步代码之前,将用var声明的任何变量的名称添加到作用域(值为undefined )。 (More: Poor, misunderstood var ) (更多: 可怜,被误解的var

  2. Function declarations are 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.) (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 foo works. 这就是为什么对foo的调用起作用的原因。 (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. 我更喜欢将其视为源中的两次遍历:第一遍进行声明,第二遍执行逐步的代码。

(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 let and const variable 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 slightly like hoisting in that they prevent access to a shadowed variable in a containing scope even before the let x or whatever line].) (旁注2:ES2015 [ES6]引入了letconst变量声明,它们的行为与var有所不同。您不能用它们声明两次变量,它们具有块作用域,并且不能在变量之前使用变量。声明,声明它们的位置。因此,它们基本上不被吊起([ 有点像吊起,因为它们甚至在let x或任何行之前也阻止了对包含范围内的阴影变量的访问)。)


More detail, and possibly getting a bit technical: 更多细节,可能还会有一些技术性:

var

If var happens 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; var x; part happens before the stepwise code, the x = 1; 部分发生在逐步代码之前, x = 1; part is stepwise code and is executed when we reach it in the sequence. part是逐步的代码,当我们按顺序到达时执行。 So: 所以:

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 . JavaScript有两个不同但外观非常相似的东西:函数声明和函数表达式 You can tell which is which by whether you're using the resulting function as part of the expression in which it's defined. 通过是否将结果函数用作定义它的表达式的一部分,您可以确定哪个是哪个。

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 named function 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. 这是完全合法且合法的JavaScript,其目的是创建一个具有适当名称( foo )的函数作为逐步代码的一部分。 The name of the function is not added to the scope (as it would be if it were a function declaration). 函数名称添加到范围中(就像它是函数声明一样)。

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引擎)使它们完全错误 ,在两个不同的时间创建了两个单独的函数。

JavaScript is event-driven, the program written in JavaScript doesn't have a start and an end. JavaScript是事件驱动的,用JavaScript编写的程序没有开始和结束。 You can compare it to any desktop UI toolkit, where you handle button clicks and key presses, but there is no obvious main once the program is initialized. 您可以将其与任何桌面UI工具箱进行比较,在该工具箱中您可以处理按钮单击和按键操作,但是一旦程序初始化,就没有明显的main

For instance there is a window.onload event that is triggered when the page is loaded - and which you can handle. 例如,有一个window.onload事件在页面加载时触发-您可以处理。

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.) (这不排除解析和编译代码,只要这些过程不影响所描述的指称语义即可。)

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需要进行编译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM