Chapter 1. Introduction to JavaScript

JavaScript is the programming language of the web. The overwhelming majority of websites use JavaScript, and all modern web browsers—on desktops, tablets, and phones—include JavaScript interpreters, making JavaScript the most-deployed programming language in history. Over the last decade, Node.js has enabled JavaScript programming outside of web browsers, and the dramatic success of Node means that JavaScript is now also the most-used programming language among software developers. Whether you’re starting from scratch or are already using JavaScript professionally, this book will help you master the language.

JavaScript是web的编程语言。绝大多数的网站都使用JavaScript,所有的现代网络浏览器——台式机、平板电脑和手机——都包括JavaScript解释器,这使得JavaScript成为历史上部署最多的编程语言。在过去的十年中,Node.js使得JavaScript编程可以在web浏览器之外进行,Node的巨大成功意味着JavaScript现在也是软件开发人员最常用的编程语言。无论你是从零开始还是已经开始专业地使用JavaScript,这本书都会帮助你掌握这门语言。

If you are already familiar with other programming languages, it may help you to know that JavaScript is a high-level, dynamic, interpreted programming language that is well-suited to object-oriented and functional programming styles. JavaScript’s variables are untyped. Its syntax is loosely based on Java, but the languages are otherwise unrelated. JavaScript derives its first-class functions from Scheme and its prototype-based inheritance from the little-known language Self. But you do not need to know any of those languages, or be familiar with those terms, to use this book and learn JavaScript.

如果您已经熟悉了其他编程语言,那么了解JavaScript是一种高级的、动态的、解释的编程语言可能会对您有所帮助,它非常适合面向对象和函数式编程风格。JavaScript的变量是无类型的。它的语法松散地基于Java,但是这两种语言在其他方面是无关的。JavaScript从Scheme派生一流函数,从鲜为人知的Self继承基于原型的函数。但您不需要了解任何这些语言,或熟悉这些术语,以使用这本书和学习JavaScript。

The name “JavaScript” is quite misleading. Except for a superficial syntactic resemblance, JavaScript is completely different from the Java programming language. And JavaScript has long since outgrown its scripting-language roots to become a robust and efficient general-purpose language suitable for serious software engineering and projects with huge codebases.

“JavaScript”这个名称很容易引起误解。除了表面上的语法相似之外,JavaScript与Java编程语言完全不同。而且JavaScript早已超越了它的脚本语言根基,成为一种健壮、高效的通用语言,适合于具有巨大代码库的严肃软件工程和项目。

JAVASCRIPT: NAMES, VERSIONS, AND MODES

JavaScript was created at Netscape in the early days of the web, and technically, “JavaScript” is a trademark licensed from Sun Microsystems (now Oracle) used to describe Netscape’s (now Mozilla’s) implementation of the language. Netscape submitted the language for standardization to ECMA—the European Computer Manufacturer’s Association—and because of trademark issues, the standardized version of the language was stuck with the awkward name “ECMAScript.” In practice, everyone just calls the language JavaScript. This book uses the name “ECMAScript” and the abbreviation “ES” to refer to the language standard and to versions of that standard.

JavaScript是在网络早期由网景公司创建的,从技术上讲,“JavaScript”是太阳微系统公司(现在的甲骨文公司)授权的商标,用来描述网景公司(现在的Mozilla公司)对该语言的实现。网景公司将这种语言提交给欧洲计算机制造商协会(ecma)进行标准化,但由于商标问题,这种语言的标准化版本只能使用一个尴尬的名字“ECMAScript”。实际上,每个人都称这种语言为JavaScript。本书使用名称“ECMAScript”和缩写“ES”来表示该语言标准和该标准的版本。

For most of the 2010s, version 5 of the ECMAScript standard has been supported by all web browsers. This book treats ES5 as the compatibility baseline and no longer discusses earlier versions of the language. ES6 was released in 2015 and added major new features—including class and module syntax—that changed JavaScript from a scripting language into a serious, general-purpose language suitable for large-scale software engineering. Since ES6, the ECMAScript specification has moved to a yearly release cadence, and versions of the language—ES2016, ES2017, ES2018, ES2019, and ES2020—are now identified by year of release.

对于2010年代的大多数版本,所有web浏览器都支持ECMAScript标准的第5版。本书将ES5作为兼容性基线,不再讨论该语言的早期版本。ES6于2015年发布,增加了主要的新特性(包括类和模块语法),使JavaScript从一种脚本语言变成了一种严肃的、适用于大规模软件工程的通用语言。自ES6以来,ECMAScript规范已经以每年发布一次为基调,该语言的版本——es2016、ES2017、ES2018、ES2019和es2020——现在以发布年份来确定。

As JavaScript evolved, the language designers attempted to correct flaws in the early (pre-ES5) versions. In order to maintain backward compatibility, it is not possible to remove legacy features, no matter how flawed. But in ES5 and later, programs can opt in to JavaScript’s strict mode in which a number of early language mistakes have been corrected. The mechanism for opting in is the “use strict” directive described in §5.6.3. That section also summarizes the differences between legacy JavaScript and strict JavaScript. In ES6 and later, the use of new language features often implicitly invokes strict mode. For example, if you use the ES6 class keyword or create an ES6 module, then all the code within the class or module is automatically strict, and the old, flawed features are not available in those contexts. This book will cover the legacy features of JavaScript but is careful to point out that they are not available in strict mode.

随着JavaScript的发展,语言设计者试图纠正早期版本(es5之前)的缺陷。为了保持向后兼容性,不可能删除遗留特性,无论其缺陷有多大。但在ES5及以后版本中,程序可以选择使用JavaScript的严格模式,在这种模式中,早期的一些语言错误已经得到了纠正。选择加入的机制是§5.6.3中描述的“严格使用”指令。这一节还总结了传统JavaScript和严格JavaScript之间的区别。在ES6及以后版本中,使用新的语言特性通常会隐式地调用strict模式。例如,如果您使用ES6类关键字或创建ES6模块,那么类或模块中的所有代码将自动严格,并且在这些上下文中不能使用旧的、有缺陷的特性。这本书将涵盖JavaScript的遗留特性,但小心地指出,它们在严格模式下是不可用的。

To be useful, every language must have a platform, or standard library, for performing things like basic input and output. The core JavaScript language defines a minimal API for working with numbers, text, arrays, sets, maps, and so on, but does not include any input or output functionality. Input and output (as well as more sophisticated features, such as networking, storage, and graphics) are the responsibility of the “host environment” within which JavaScript is embedded.

要想有用,每种语言都必须有一个平台或标准库来执行基本输入和输出之类的操作。核心JavaScript语言定义了处理数字、文本、数组、集合、映射等的最小API,但不包括任何输入或输出功能。输入和输出(以及更复杂的特性,如网络、存储和图形)由嵌入JavaScript的“主机环境”负责。

The original host environment for JavaScript was a web browser, and this is still the most common execution environment for JavaScript code. The web browser environment allows JavaScript code to obtain input from the user’s mouse and keyboard and by making HTTP requests. And it allows JavaScript code to display output to the user with HTML and CSS.

JavaScript的原始宿主环境是一个web浏览器,这仍然是JavaScript代码最常见的执行环境。web浏览器环境允许JavaScript代码通过发送HTTP请求从用户的鼠标和键盘获取输入。它允许JavaScript代码用HTML和CSS向用户显示输出。

Since 2010, another host environment has been available for JavaScript code. Instead of constraining JavaScript to work with the APIs provided by a web browser, Node gives JavaScript access to the entire operating system, allowing JavaScript programs to read and write files, send and receive data over the network, and make and serve HTTP requests. Node is a popular choice for implementing web servers and also a convenient tool for writing simple utility scripts as an alternative to shell scripts.

从2010年开始,另一个主机环境已经可以用于JavaScript代码。Node没有限制JavaScript使用web浏览器提供的api,而是允许JavaScript访问整个操作系统,允许JavaScript程序读和写文件,通过网络发送和接收数据,以及发出和服务HTTP请求。Node是实现web服务器的常用选择,也是编写简单实用程序脚本的方便工具,可以作为shell脚本的替代。

Most of this book is focused on the JavaScript language itself. Chapter 11 documents the JavaScript standard library, Chapter 15 introduces the web browser host environment, and Chapter 16 introduces the Node host environment.

这本书的大部分内容都集中在JavaScript语言本身。第11章介绍了JavaScript标准库,第15章介绍了web浏览器主机环境,第16章介绍了节点主机环境。

This book covers low-level fundamentals first, and then builds on those to more advanced and higher-level abstractions. The chapters are intended to be read more or less in order. But learning a new programming language is never a linear process, and describing a language is not linear either: each language feature is related to other features, and this book is full of cross-references—sometimes backward and sometimes forward—to related material. This introductory chapter makes a quick first pass through the language, introducing key features that will make it easier to understand the in-depth treatment in the chapters that follow. If you are already a practicing JavaScript programmer, you can probably skip this chapter. (Although you might enjoy reading Example 1-1 at the end of the chapter before you move on.)

这本书首先介绍了底层基础知识,然后在这些基础上构建更高级和更高级别的抽象。这些章节的目的是让读者或多或少地按顺序阅读。但是学习一种新的编程语言从来都不是一个线性的过程,描述一种语言也不是线性的:每一种语言的特性都与其他特性相关,这本书充满了交叉引用——有时向后,有时向前的相关材料。这一介绍性章节对该语言进行了一次快速的介绍,并介绍了一些关键特性,这些特性将使后续章节的深入处理更容易理解。如果你已经是一个实践JavaScript程序员,你可以跳过这一章。(尽管你可能会喜欢阅读本章末尾的示例1-1,然后再继续阅读。)

1.1 Exploring JavaScript

When learning a new programming language, it’s important to try the examples in the book, then modify them and try them again to test your understanding of the language. To do that, you need a JavaScript interpreter.

在学习一门新的编程语言时,试一试书中的例子是很重要的,然后修改它们,再试一次来测试你对这门语言的理解。为此,需要一个JavaScript解释器。

The easiest way to try out a few lines of JavaScript is to open up the web developer tools in your web browser (with F12, Ctrl-Shift-I, or Command-Option-I) and select the Console tab. You can then type code at the prompt and see the results as you type. Browser developer tools often appear as panes at the bottom or right of the browser window, but you can usually detach them as separate windows (as pictured in Figure 1-1), which is often quite convenient.

尝试几行JavaScript的最简单方法是在web浏览器中打开web developer工具(使用F12、Ctrl-Shift-I或Command-Option-I)并选择Console选项卡。然后可以在提示符处键入代码,并在键入时查看结果。浏览器开发人员工具通常以窗格的形式出现在浏览器窗口的底部或右侧,但是您通常可以将它们分离为单独的窗口(如图1-1所示),这通常非常方便。

The JavaScript console in Firefox’s Developer Tools

Another way to try out JavaScript code is to download and install Node from https://nodejs.org. Once Node is installed on your system, you can simply open a Terminal window and type node to begin an interactive JavaScript session like this one:

另一种尝试JavaScript代码的方法是从https://nodejs.org下载并安装Node。一旦在你的系统上安装了Node,你可以简单地打开一个终端窗口,输入Node来开始一个交互式的JavaScript会话,就像这样:

  1. $ node
  2. Welcome to Node.js v12.13.0.
  3. Type ".help" for more information.
  4. > .help
  5. .break Sometimes you get stuck, this gets you out
  6. .clear Alias for .break
  7. .editor Enter editor mode
  8. .exit Exit the repl
  9. .help Print this help message
  10. .load Load JS from a file into the REPL session
  11. .save Save all evaluated commands in this REPL session to a file
  12. Press ^C to abort current expression, ^D to exit the repl
  13. > let x = 2, y = 3;
  14. undefined
  15. > x + y
  16. 5
  17. > (x === 2) && (y === 3)
  18. true
  19. > (x > 3) || (y < 3)
  20. false

1.2 Hello World

When you are ready to start experimenting with longer chunks of code, these line-by-line interactive environments may no longer be suitable, and you will probably prefer to write your code in a text editor. From there, you can copy and paste to the JavaScript console or into a Node session. Or you can save your code to a file (the traditional filename extension for JavaScript code is .js) and then run that file of JavaScript code with Node:

当您准备开始尝试更长的代码块时,这些逐行交互环境可能不再适合,您可能更喜欢在文本编辑器中编写代码。从那里,您可以复制并粘贴到JavaScript控制台或节点会话中。或者你可以将你的代码保存到一个文件中(传统的JavaScript代码的文件名扩展名是.js),然后用Node运行该JavaScript代码文件:

  1. $ node snippet.js

If you use Node in a noninteractive manner like this, it won’t automatically print out the value of all the code you run, so you’ll have to do that yourself. You can use the function console.log() to display text and other JavaScript values in your terminal window or in a browser’s developer tools console. So, for example, if you create a hello.js file containing this line of code:

如果像这样以非交互的方式使用Node,它不会自动打印出您运行的所有代码的值,因此您必须自己执行。可以使用console.log()函数在终端窗口或浏览器的developer tools控制台中显示文本和其他JavaScript值。因此,例如,如果你创建一个hello.js文件,其中包含这行代码:

  1. console.log("Hello World!");

and execute the file with node hello.js, you’ll see the message “Hello World!” printed out.

并使用节点hello执行文件。js,你会看到消息“Hello World!””打印出来。

If you want to see that same message printed out in the JavaScript console of a web browser, create a new file named hello.html, and put this text in it:

如果您想在web浏览器的JavaScript控制台中看到同样的消息打印出来,那么创建一个名为 hello.html 的文件。,并把这段文字:

  1. <script src="hello.js"></script>

Then load hello.html into your web browser using a file:// URL like this one:

然后使用 file:// URL将 hello.html 加载到浏览器中,如下图所示:

  1. file:///Users/username/javascript/hello.html

Open the developer tools window to see the greeting in the console.

打开developer tools窗口,在控制台中查看问候语。

1.3 A Tour of JavaScript

This section presents a quick introduction, through code examples, to the JavaScript language. After this introductory chapter, we dive into JavaScript at the lowest level: Chapter 2 explains things like JavaScript comments, semicolons, and the Unicode character set. Chapter 3 starts to get more interesting: it explains JavaScript variables and the values you can assign to those variables.

本节通过代码示例快速介绍JavaScript语言。在这一介绍性章节之后,我们将深入到JavaScript的底层:第2章解释了JavaScript注释、分号和Unicode字符集等内容。第3章开始变得更有趣:它解释了JavaScript变量和你可以为这些变量赋值的值。

Here’s some sample code to illustrate the highlights of those two chapters:

下面是一些示例代码,演示这两章的重点内容:

  1. // Anything following double slashes is an English-language comment.
  2. // Read the comments carefully: they explain the JavaScript code.
  3. // A variable is a symbolic name for a value.
  4. // Variables are declared with the let keyword:
  5. let x; // Declare a variable named x.
  6. // Values can be assigned to variables with an = sign
  7. x = 0; // Now the variable x has the value 0
  8. x // => 0: A variable evaluates to its value.
  9. // JavaScript supports several types of values
  10. x = 1; // Numbers.
  11. x = 0.01; // Numbers can be integers or reals.
  12. x = "hello world"; // Strings of text in quotation marks.
  13. x = 'JavaScript'; // Single quote marks also delimit strings.
  14. x = true; // A Boolean value.
  15. x = false; // The other Boolean value.
  16. x = null; // Null is a special value that means "no value."
  17. x = undefined; // Undefined is another special value like null.

Two other very important types that JavaScript programs can manipulate are objects and arrays. These are the subjects of Chapters 6 and 7, but they are so important that you’ll see them many times before you reach those chapters:

  1. // JavaScript's most important datatype is the object.
  2. // An object is a collection of name/value pairs, or a string to value map.
  3. let book = { // Objects are enclosed in curly braces.
  4. topic: "JavaScript", // The property "topic" has value "JavaScript."
  5. edition: 7 // The property "edition" has value 7
  6. }; // The curly brace marks the end of the object.
  7. // Access the properties of an object with . or []:
  8. book.topic // => "JavaScript"
  9. book["edition"] // => 7: another way to access property values.
  10. book.author = "Flanagan"; // Create new properties by assignment.
  11. book.contents = {}; // {} is an empty object with no properties.
  12. // Conditionally access properties with ?. (ES2020):
  13. book.contents?.ch01?.sect1 // => undefined: book.contents has no ch01 property.
  14. // JavaScript also supports arrays (numerically indexed lists) of values:
  15. let primes = [2, 3, 5, 7]; // An array of 4 values, delimited with [ and ].
  16. primes[0] // => 2: the first element (index 0) of the array.
  17. primes.length // => 4: how many elements in the array.
  18. primes[primes.length-1] // => 7: the last element of the array.
  19. primes[4] = 9; // Add a new element by assignment.
  20. primes[4] = 11; // Or alter an existing element by assignment.
  21. let empty = []; // [] is an empty array with no elements.
  22. empty.length // => 0
  23. // Arrays and objects can hold other arrays and objects:
  24. let points = [ // An array with 2 elements.
  25. {x: 0, y: 0}, // Each element is an object.
  26. {x: 1, y: 1}
  27. ];
  28. let data = { // An object with 2 properties
  29. trial1: [[1,2], [3,4]], // The value of each property is an array.
  30. trial2: [[2,3], [4,5]] // The elements of the arrays are arrays.
  31. };

COMMENT SYNTAX IN CODE EXAMPLES

You may have noticed in the preceding code that some of the comments begin with an arrow (=>). These show the value produced by the code before the comment and are my attempt to emulate an interactive JavaScript environment like a web browser console in a printed book.

您可能已经注意到,在前面的代码中,一些注释以箭头开头(=>)。这些代码显示了注释之前代码产生的值,我试图模拟交互式JavaScript环境,就像印刷书籍中的web浏览器控制台一样。

Those // => comments also serve as an assertion, and I’ve written a tool that tests the code and verifies that it produces the value specified in the comment. This should help, I hope, to reduce errors in the book.

那些// =>注释也用作断言,我编写了一个工具来测试代码并验证它是否生成注释中指定的值。我希望这有助于减少书中的错误。

There are two related styles of comment/assertion. If you see a comment of the form // a == 42, it means that after the code before the comment runs, the variable a will have the value 42. If you see a comment of the form // !, it means that the code on the line before the comment throws an exception (and the rest of the comment after the exclamation mark usually explains what kind of exception is thrown).

注释/断言有两种相关的风格。如果您看到// a == 42形式的注释,这意味着在注释运行之前的代码之后,变量a的值将是42。如果您看到// !形式的注释,这意味着注释前一行的代码抛出一个异常(感叹号之后的注释的其余部分通常解释抛出的是哪种异常)。

You’ll see these comments used throughout the book.

您将在整本书中看到这些注释。

The syntax illustrated here for listing array elements within square braces or mapping object property names to property values inside curly braces is known as an initializer expression, and it is just one of the topics of Chapter 4. An expression is a phrase of JavaScript that can be evaluated to produce a value. For example, the use of . and [] to refer to the value of an object property or array element is an expression.

这里演示的在方括号内列出数组元素或在花括号内将对象属性名映射到属性值的语法称为初始化表达式,它只是第4章的主题之一。表达式是JavaScript的一个短语,可以计算它来产生一个值。例如,的使用。和[]引用对象属性或数组元素的值是一个表达式。

One of the most common ways to form expressions in JavaScript is to use operators:

  1. // Operators act on values (the operands) to produce a new value.
  2. // Arithmetic operators are some of the simplest:
  3. 3 + 2 // => 5: addition
  4. 3 - 2 // => 1: subtraction
  5. 3 * 2 // => 6: multiplication
  6. 3 / 2 // => 1.5: division
  7. points[1].x - points[0].x // => 1: more complicated operands also work
  8. "3" + "2" // => "32": + adds numbers, concatenates strings
  9. // JavaScript defines some shorthand arithmetic operators
  10. let count = 0; // Define a variable
  11. count++; // Increment the variable
  12. count--; // Decrement the variable
  13. count += 2; // Add 2: same as count = count + 2;
  14. count *= 3; // Multiply by 3: same as count = count * 3;
  15. count // => 6: variable names are expressions, too.
  16. // Equality and relational operators test whether two values are equal,
  17. // unequal, less than, greater than, and so on. They evaluate to true or false.
  18. let x = 2, y = 3; // These = signs are assignment, not equality tests
  19. x === y // => false: equality
  20. x !== y // => true: inequality
  21. x < y // => true: less-than
  22. x <= y // => true: less-than or equal
  23. x > y // => false: greater-than
  24. x >= y // => false: greater-than or equal
  25. "two" === "three" // => false: the two strings are different
  26. "two" > "three" // => true: "tw" is alphabetically greater than "th"
  27. false === (x > y) // => true: false is equal to false
  28. // Logical operators combine or invert boolean values
  29. (x === 2) && (y === 3) // => true: both comparisons are true. && is AND
  30. (x > 3) || (y < 3) // => false: neither comparison is true. || is OR
  31. !(x === y) // => true: ! inverts a boolean value

If JavaScript expressions are like phrases, then JavaScript statements are like full sentences. Statements are the topic of Chapter 5. Roughly, an expression is something that computes a value but doesn’t do anything: it doesn’t alter the program state in any way. Statements, on the other hand, don’t have a value, but they do alter the state. You’ve seen variable declarations and assignment statements above. The other broad category of statement is control structures, such as conditionals and loops. You’ll see examples below, after we cover functions.

如果JavaScript表达式像短语,那么JavaScript语句就像完整的句子。陈述是第5章的主题。粗略地说,表达式是计算一个值但不做任何事情的东西:它不以任何方式改变程序状态。另一方面,语句没有值,但是它们可以改变状态。您已经在上面看到了变量声明和赋值语句。语句的另一大类是控制结构,比如条件语句和循环。在介绍函数之后,您将看到下面的示例。

A function is a named and parameterized block of JavaScript code that you define once, and can then invoke over and over again. Functions aren’t covered formally until Chapter 8, but like objects and arrays, you’ll see them many times before you get to that chapter. Here are some simple examples:

函数是一个已命名和参数化的JavaScript代码块,您只定义一次,然后可以反复调用它。函数直到第8章才正式介绍,但就像对象和数组一样,在进入这一章之前,您将多次看到它们。下面是一些简单的例子:

  1. // Functions are parameterized blocks of JavaScript code that we can invoke.
  2. function plus1(x) { // Define a function named "plus1" with parameter "x"
  3. return x + 1; // Return a value one larger than the value passed in
  4. } // Functions are enclosed in curly braces
  5. plus1(y) // => 4: y is 3, so this invocation returns 3+1
  6. let square = function(x) { // Functions are values and can be assigned to vars
  7. return x * x; // Compute the function's value
  8. }; // Semicolon marks the end of the assignment.
  9. square(plus1(y)) // => 16: invoke two functions in one expression

In ES6 and later, there is a shorthand syntax for defining functions. This concise syntax uses => to separate the argument list from the function body, so functions defined this way are known as arrow functions. Arrow functions are most commonly used when you want to pass an unnamed function as an argument to another function. The preceding code looks like this when rewritten to use arrow functions:

在ES6及以后版本中,有一种用于定义函数的快捷语法。这种简洁的语法使用=>将参数列表与函数体分开,因此以这种方式定义的函数称为箭头函数。当您希望将一个未命名的函数作为参数传递给另一个函数时,最常用的是箭头函数。前面的代码看起来像这样,当重写使用箭头函数:

  1. const plus1 = x => x + 1; // The input x maps to the output x + 1
  2. const square = x => x * x; // The input x maps to the output x * x
  3. plus1(y) // => 4: function invocation is the same
  4. square(plus1(y)) // => 16

When we use functions with objects, we get methods:

当我们使用函数和对象时,我们得到方法:

  1. // When functions are assigned to the properties of an object, we call
  2. // them "methods." All JavaScript objects (including arrays) have methods:
  3. let a = []; // Create an empty array
  4. a.push(1,2,3); // The push() method adds elements to an array
  5. a.reverse(); // Another method: reverse the order of elements
  6. // We can define our own methods, too. The "this" keyword refers to the object
  7. // on which the method is defined: in this case, the points array from earlier.
  8. points.dist = function() { // Define a method to compute distance between points
  9. let p1 = this[0]; // First element of array we're invoked on
  10. let p2 = this[1]; // Second element of the "this" object
  11. let a = p2.x-p1.x; // Difference in x coordinates
  12. let b = p2.y-p1.y; // Difference in y coordinates
  13. return Math.sqrt(a*a + // The Pythagorean theorem
  14. b*b); // Math.sqrt() computes the square root
  15. };
  16. points.dist() // => Math.sqrt(2): distance between our 2 points

Now, as promised, here are some functions whose bodies demonstrate common JavaScript control structure statements:

现在,如前所述,下面是一些函数,它们的主体演示了常见的JavaScript控制结构语句:

  1. // JavaScript statements include conditionals and loops using the syntax
  2. // of C, C++, Java, and other languages.
  3. function abs(x) { // A function to compute the absolute value.
  4. if (x >= 0) { // The if statement...
  5. return x; // executes this code if the comparison is true.
  6. } // This is the end of the if clause.
  7. else { // The optional else clause executes its code if
  8. return -x; // the comparison is false.
  9. } // Curly braces optional when 1 statement per clause.
  10. } // Note return statements nested inside if/else.
  11. abs(-10) === abs(10) // => true
  12. function sum(array) { // Compute the sum of the elements of an array
  13. let sum = 0; // Start with an initial sum of 0.
  14. for(let x of array) { // Loop over array, assigning each element to x.
  15. sum += x; // Add the element value to the sum.
  16. } // This is the end of the loop.
  17. return sum; // Return the sum.
  18. }
  19. sum(primes) // => 28: sum of the first 5 primes 2+3+5+7+11
  20. function factorial(n) { // A function to compute factorials
  21. let product = 1; // Start with a product of 1
  22. while(n > 1) { // Repeat statements in {} while expr in () is true
  23. product *= n; // Shortcut for product = product * n;
  24. n--; // Shortcut for n = n - 1
  25. } // End of loop
  26. return product; // Return the product
  27. }
  28. factorial(4) // => 24: 1*4*3*2
  29. function factorial2(n) { // Another version using a different loop
  30. let i, product = 1; // Start with 1
  31. for(i=2; i <= n; i++) // Automatically increment i from 2 up to n
  32. product *= i; // Do this each time. {} not needed for 1-line loops
  33. return product; // Return the factorial
  34. }
  35. factorial2(5) // => 120: 1*2*3*4*5

JavaScript supports an object-oriented programming style, but it is significantly different than “classical” object-oriented programming languages. Chapter 9 covers object-oriented programming in JavaScript in detail, with lots of examples. Here is a very simple example that demonstrates how to define a JavaScript class to represent 2D geometric points. Objects that are instances of this class have a single method, named distance(), that computes the distance of the point from the origin:

JavaScript支持面向对象的编程风格,但它与“经典的”面向对象编程语言有显著的不同。第9章详细介绍了JavaScript的面向对象编程,并提供了很多示例。下面是一个非常简单的示例,演示了如何定义一个JavaScript类来表示2D几何点。作为这个类的实例的对象有一个名为distance()的方法,它计算点到原点的距离:

  1. class Point { // By convention, class names are capitalized.
  2. constructor(x, y) { // Constructor function to initialize new instances.
  3. this.x = x; // This keyword is the new object being initialized.
  4. this.y = y; // Store function arguments as object properties.
  5. } // No return is necessary in constructor functions.
  6. distance() { // Method to compute distance from origin to point.
  7. return Math.sqrt( // Return the square root of x² + y².
  8. this.x * this.x + // this refers to the Point object on which
  9. this.y * this.y // the distance method is invoked.
  10. );
  11. }
  12. }
  13. // Use the Point() constructor function with "new" to create Point objects
  14. let p = new Point(1, 1); // The geometric point (1,1).
  15. // Now use a method of the Point object p
  16. p.distance() // => Math.SQRT2

This introductory tour of JavaScript’s fundamental syntax and capabilities ends here, but the book continues with self-contained chapters that cover additional features of the language:

关于JavaScript基本语法和能力的介绍到此结束,但这本书继续以自成体系的章节介绍该语言的其他特性:

Chapter 10, Modules Shows how JavaScript code in one file or script can use JavaScript functions and classes defined in other files or scripts.

Chapter 11, The JavaScript Standard Library Covers the built-in functions and classes that are available to all JavaScript programs. This includes important data stuctures like maps and sets, a regular expression class for textual pattern matching, functions for serializing JavaScript data structures, and much more.

Chapter 12, Iterators and Generators Explains how the for/of loop works and how you can make your own classes iterable with for/of. It also covers generator functions and the yield statement.

Chapter 13, Asynchronous JavaScript This chapter is an in-depth exploration of asynchronous programming in JavaScript, covering callbacks and events, Promise-based APIs, and the async and await keywords. Although the core JavaScript language is not asynchronous, asynchronous APIs are the default in both web browsers and Node, and this chapter explains the techniques for working with those APIs.

Chapter 14, Metaprogramming Introduces a number of advanced features of JavaScript that may be of interest to programmers writing libraries of code for other JavaScript programmers to use.

Chapter 15, JavaScript in Web Browsers Introduces the web browser host environment, explains how web browsers execute JavaScript code, and covers the most important of the many APIs defined by web browsers. This is by far the longest chapter in the book.

Chapter 16, Server-Side JavaScript with Node Introduces the Node host environment, covering the fundamental programming model and the data structures and APIs that are most important to understand.

Chapter 17, JavaScript Tools and Extensions Covers tools and language extensions that are worth knowing about because they are widely used and may make you a more productive programmer.

1.4 Example: Character Frequency Histograms

This chapter concludes with a short but nontrivial JavaScript program. Example 1-1 is a Node program that reads text from standard input, computes a character frequency histogram from that text, and then prints out the histogram. You could invoke the program like this to analyze the character frequency of its own source code:

本章以一个简短但不平凡的JavaScript程序结束。示例1-1是一个节点程序,它从标准输入中读取文本,根据文本计算字符频率直方图,然后打印该直方图。你可以调用这样的程序来分析字符频率自己的源代码:

  1. $ node charfreq.js < charfreq.js
  2. T: ########### 11.22%
  3. E: ########## 10.15%
  4. R: ####### 6.68%
  5. S: ###### 6.44%
  6. A: ###### 6.16%
  7. N: ###### 5.81%
  8. O: ##### 5.45%
  9. I: ##### 4.54%
  10. H: #### 4.07%
  11. C: ### 3.36%
  12. L: ### 3.20%
  13. U: ### 3.08%
  14. /: ### 2.88%

This example uses a number of advanced JavaScript features and is intended to demonstrate what real-world JavaScript programs can look like. You should not expect to understand all of the code yet, but be assured that all of it will be explained in the chapters that follow.

这个示例使用了许多高级JavaScript特性,旨在演示真实的JavaScript程序是什么样的。你不应该期望理解所有的代码,但是要确保所有的代码将在下面的章节中被解释。

Example 1-1. Computing character frequency histograms with JavaScript

  1. /**
  2. * This Node program reads text from standard input, computes the frequency
  3. * of each letter in that text, and displays a histogram of the most
  4. * frequently used characters. It requires Node 12 or higher to run.
  5. *
  6. * In a Unix-type environment you can invoke the program like this:
  7. * node charfreq.js < corpus.txt
  8. */
  9. // This class extends Map so that the get() method returns the specified
  10. // value instead of null when the key is not in the map
  11. class DefaultMap extends Map {
  12. constructor(defaultValue) {
  13. super(); // Invoke superclass constructor
  14. this.defaultValue = defaultValue; // Remember the default value
  15. }
  16. get(key) {
  17. if (this.has(key)) { // If the key is already in the map
  18. return super.get(key); // return its value from superclass.
  19. }
  20. else {
  21. return this.defaultValue; // Otherwise return the default value
  22. }
  23. }
  24. }
  25. // This class computes and displays letter frequency histograms
  26. class Histogram {
  27. constructor() {
  28. this.letterCounts = new DefaultMap(0); // Map from letters to counts
  29. this.totalLetters = 0; // How many letters in all
  30. }
  31. // This function updates the histogram with the letters of text.
  32. add(text) {
  33. // Remove whitespace from the text, and convert to upper case
  34. text = text.replace(/\s/g, "").toUpperCase();
  35. // Now loop through the characters of the text
  36. for(let character of text) {
  37. let count = this.letterCounts.get(character); // Get old count
  38. this.letterCounts.set(character, count+1); // Increment it
  39. this.totalLetters++;
  40. }
  41. }
  42. // Convert the histogram to a string that displays an ASCII graphic
  43. toString() {
  44. // Convert the Map to an array of [key,value] arrays
  45. let entries = [...this.letterCounts];
  46. // Sort the array by count, then alphabetically
  47. entries.sort((a,b) => { // A function to define sort order.
  48. if (a[1] === b[1]) { // If the counts are the same
  49. return a[0] < b[0] ? -1 : 1; // sort alphabetically.
  50. } else { // If the counts differ
  51. return b[1] - a[1]; // sort by largest count.
  52. }
  53. });
  54. // Convert the counts to percentages
  55. for(let entry of entries) {
  56. entry[1] = entry[1] / this.totalLetters*100;
  57. }
  58. // Drop any entries less than 1%
  59. entries = entries.filter(entry => entry[1] >= 1);
  60. // Now convert each entry to a line of text
  61. let lines = entries.map(
  62. ([l,n]) => `${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%`
  63. );
  64. // And return the concatenated lines, separated by newline characters.
  65. return lines.join("\n");
  66. }
  67. }
  68. // This async (Promise-returning) function creates a Histogram object,
  69. // asynchronously reads chunks of text from standard input, and adds those chunks to
  70. // the histogram. When it reaches the end of the stream, it returns this histogram
  71. async function histogramFromStdin() {
  72. process.stdin.setEncoding("utf-8"); // Read Unicode strings, not bytes
  73. let histogram = new Histogram();
  74. for await (let chunk of process.stdin) {
  75. histogram.add(chunk);
  76. }
  77. return histogram;
  78. }
  79. // This one final line of code is the main body of the program.
  80. // It makes a Histogram object from standard input, then prints the histogram.
  81. histogramFromStdin().then(histogram => { console.log(histogram.toString()); });

1.5 Summary

This book explains JavaScript from the bottom up. This means that we start with low-level details like comments, identifiers, variables, and types; then build to expressions, statements, objects, and functions; and then cover high-level language abstractions like classes and modules. I take the word definitive in the title of this book seriously, and the coming chapters explain the language at a level of detail that may feel off-putting at first. True mastery of JavaScript requires an understanding of the details, however, and I hope that you will make time to read this book cover to cover. But please don’t feel that you need to do that on your first reading. If you find yourself feeling bogged down in a section, simply skip to the next. You can come back and master the details once you have a working knowledge of the language as a whole.

这本书从下至上地解释了JavaScript。这意味着我们从底层细节开始,比如注释、标识符、变量和类型;然后构建表达式、语句、对象和函数;然后介绍高级语言抽象,比如类和模块。我在这本书的标题中认真地使用了“权威”这个词,接下来的章节会详细地解释这种语言,一开始可能会让人感到不快。然而,真正掌握JavaScript需要了解细节,我希望您能抽出时间从头到尾阅读这本书。但请不要觉得在第一次阅读时就需要这样做。如果你发现自己在某个章节陷入困境,直接跳到下一个章节。一旦你对语言有了整体的应用知识,你可以回过头来掌握细节。