JavaScript 模块

本指南为您提供开始使用 JavaScript 模块语法所需的一切。

模块背景

JavaScript programs started off pretty small — most of its usage in the early days was to do isolated scripting tasks, providing a bit of interactivity to your web pages where needed, so large scripts were generally not needed. Fast forward a few years and we now have complete applications being run in browsers with a lot of JavaScript, as well as JavaScript being used in other contexts ( Node.js , for example).

It has therefore made sense in recent years to start thinking about providing mechanisms for splitting JavaScript programs up into separate modules that can be imported when needed. Node.js has had this ability for a long time, and there are a number of JavaScript libraries and frameworks that enable module usage (for example, other CommonJS and AMD -based module systems like RequireJS , and more recently Webpack and Babel ).

The good news is that modern browsers have started to support module functionality natively, and this is what this article is all about. This can only be a good thing — browsers can optimize loading of modules, making it more efficient than having to use a library and do all of that extra client-side processing and extra round trips.

浏览器支持

Use of native JavaScript modules is dependent on the import and export statements; these are supported in browsers as follows:

import

更新 GitHub 上的兼容性数据
Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet Node.js
import Chrome 61 Edge 16
16
15
Disabled
Disabled From version 15: this feature is behind the Experimental JavaScript Features preference.
Firefox 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
IE 不支持 No Opera 48 Safari 10.1 WebView Android 61 Chrome Android 61 Firefox Android 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
Opera Android 45 Safari iOS 10.3 Samsung Internet Android 8.0 nodejs 13.2.0
13.2.0
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
12.0.0
Disabled
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 12.0.0: this feature is behind the --experimental-modules runtime flag.
8.5.0
Disabled
Module filenames must end with .mjs , not .js. See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 8.5.0: this feature is behind the --experimental-modules runtime flag.
Dynamic import Chrome 63 Edge 79 Firefox 67
67
不支持 66 — 67
Disabled
Disabled From version 66 until version 67 (exclusive): this feature is behind the javascript.options.dynamicImport preference (needs to be set to true ). To change preferences in Firefox, visit about:config.
IE 不支持 No Opera 50 Safari 11.1 WebView Android 63 Chrome Android 63 Firefox Android 67
67
不支持 66 — 67
Disabled
Disabled From version 66 until version 67 (exclusive): this feature is behind the javascript.options.dynamicImport preference (needs to be set to true ). To change preferences in Firefox, visit about:config.
Opera Android 46 Safari iOS 11.3 Samsung Internet Android 8.0 nodejs 13.2.0
13.2.0
Dynamic import can be used in either CommonJS or ES module files, to import either CommonJS or ES module files. See Node's ECMAScript Modules documentation 了解更多细节。
12.0.0
Disabled
Dynamic import can be used in either CommonJS or ES module files, to import either CommonJS or ES module files. See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 12.0.0: this feature is behind the --experimental-modules runtime flag.
Available in workers Chrome 80
80
67
Disabled
Disabled From version 67: this feature is behind the Experimental Web Platform Features preference. To change preferences in Chrome, visit chrome://flags.
Edge 80
80
79
Disabled
Disabled From version 79: this feature is behind the Experimental Web Platform Features preference.
Firefox 不支持 No IE 不支持 No Opera 不支持 No Safari 不支持 No WebView Android 80 Chrome Android 80
80
67
Disabled
Disabled From version 67: this feature is behind the Experimental Web Platform Features preference. To change preferences in Chrome, visit chrome://flags.
Firefox Android 不支持 No Opera Android 不支持 No Safari iOS 不支持 No Samsung Internet Android 不支持 No nodejs 不支持 No

图例

完整支持
完整支持
不支持
不支持
见实现注意事项。
见实现注意事项。
用户必须明确启用此特征。
用户必须明确启用此特征。

export

更新 GitHub 上的兼容性数据
Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet Node.js
export Chrome 61 Edge 16
16
15
Disabled
Disabled From version 15: this feature is behind the Experimental JavaScript Features preference.
Firefox 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
IE 不支持 No Opera 48 Safari 10.1 WebView Android 不支持 No Chrome Android 61 Firefox Android 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
Opera Android 45 Safari iOS 10.3 Samsung Internet Android 8.0 nodejs 13.2.0
13.2.0
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
12.0.0
Disabled
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 12.0.0: this feature is behind the --experimental-modules runtime flag.
8.5.0
Disabled
Module filenames must end with .mjs , not .js. See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 8.5.0: this feature is behind the --experimental-modules runtime flag.
default keyword with export Chrome 61 Edge 16
16
15
Disabled
Disabled From version 15: this feature is behind the Experimental JavaScript Features preference.
Firefox 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
IE 不支持 No Opera 48 Safari 10.1 WebView Android 不支持 No Chrome Android 61 Firefox Android 60
60
不支持 54 — 60
Disabled
Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference. To change preferences in Firefox, visit about:config.
Opera Android 45 Safari iOS 10.3 Samsung Internet Android 8.0 nodejs 13.2.0
13.2.0
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
12.0.0
Disabled
Modules must either have a filename ending in .mjs , or the nearest parent package.json file must contain "type": "module" . See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 12.0.0: this feature is behind the --experimental-modules runtime flag.
8.5.0
Disabled
Module filenames must end with .mjs , not .js. See Node's ECMAScript Modules documentation 了解更多细节。
Disabled From version 8.5.0: this feature is behind the --experimental-modules runtime flag.
export * as namespace Chrome 72 Edge 79 Firefox 80 IE 不支持 No Opera 60 Safari 不支持 No WebView Android 不支持 No Chrome Android 72 Firefox Android 不支持 No Opera Android 51 Safari iOS 不支持 No Samsung Internet Android 11.0 nodejs 12.0.0

图例

完整支持
完整支持
不支持
不支持
见实现注意事项。
见实现注意事项。
用户必须明确启用此特征。
用户必须明确启用此特征。

介绍范例

为演示模块用法,我们创建 简单范例集 that you can find on GitHub. These examples demonstrate a simple set of modules that create a <canvas> element on a webpage, and then draw (and report information about) different shapes on the canvas.

These are fairly trivial, but have been kept deliberately simple to demonstrate modules clearly.

注意 : If you want to download the examples and run them locally, you'll need to run them through a local web server.

基本范例结构

在第一个范例中 (见 basic-modules ) 有以下文件结构:

index.html
main.js
modules/
    canvas.js
    square.js
				

注意 : All of the examples in this guide have basically the same structure; the above should start getting pretty familiar.

The modules directory's two modules are described below:

Aside — .mjs versus .js

Throughout this article, we've used .js extensions for our module files, but in other resources you may see the .mjs extension used instead. V8's documentation recommends this , for example. The reasons given are:

However, we decided to keep to using .js , at least for the moment. To get modules to work correctly in a browser, you need to make sure that your server is serving them with a Content-Type header that contains a JavaScript MIME type such as text/javascript . If you don't, you'll get a strict MIME type checking error along the lines of "The server responded with a non-JavaScript MIME type" and the browser won't run your JavaScript. Most servers already set the correct type for .js files, but not yet for .mjs files. Servers that already serve .mjs files correctly include GitHub Pages and http-server for Node.js.

This is OK if you are using such an environment already, or if you aren't but you know what you are doing and have access (i.e. you can configure your server to set the correct Content-Type for .mjs files). It could however cause confusion if you don't control the server you are serving files from, or are publishing files for public use, as we are here.

For learning and portability purposes, we decided to keep to .js .

If you really value the clarity of using .mjs for modules versus using .js for "normal" JavaScript files, but don't want to run into the problem described above, you could always use .mjs during development and convert them to .js during your build step.

It is also worth noting that:

导出模块特征

The first thing you do to get access to module features is export them. This is done using the export 语句。

The easiest way to use it is to place it in front of any items you want exported out of the module, for example:

export const name = 'square';
export function draw(ctx, length, x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x, y, length, length);
  return {
    length: length,
    x: x,
    y: y,
    color: color
  };
}
				

可以导出函数, var , let , const , and — as we'll see later — classes. They need to be top-level items; you can't use export inside a function, for example.

A more convenient way of exporting all the items you want to export is to use a single export statement at the end of your module file, followed by a comma-separated list of the features you want to export wrapped in curly braces. For example:

export { name, draw, reportArea, reportPerimeter };
				

把特征导入脚本

一旦从模块导出某些特征,就需要将其导入脚本中才能使用它们。要做到这点,最简单方式如下:

import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
				

使用 import statement, followed by a comma-separated list of the features you want to import wrapped in curly braces, followed by the keyword from, followed by the path to the module file — a path relative to the site root, which for our basic-modules example would be /js-examples/modules/basic-modules .

However, we've written the path a bit differently — we are using the dot ( . ) syntax to mean "the current location", followed by the path beyond that to the file we are trying to find. This is much better than writing out the entire relative path each time, as it is shorter, and it makes the URL portable — the example will still work if you move it to a different location in the site hierarchy.

So for example:

/js-examples/modules/basic-modules/modules/square.js
				

becomes

./modules/square.js
				

You can see such lines in action in main.js .

注意 : In some module systems, you can omit the file extension and the dot (e.g. '/modules/square' ). This doesn't work in native JavaScript modules.

Once you've imported the features into your script, you can use them just like they were defined inside the same file. The following is found in main.js , below the import lines:

let myCanvas = create('myCanvas', document.body, 480, 320);
let reportList = createReportList(myCanvas.id);
let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
reportArea(square1.length, reportList);
reportPerimeter(square1.length, reportList);
				

注意: Although imported features are available in the file, they are read only views of the feature that was exported. You cannot change the variable that was imported, but you can still modify properties similar to const . Additionally, these features are imported as live bindings, meaning that they can change in value even if you cannot modify the binding unlike const .

把模块应用到 HTML

Now we just need to apply the main.js module to our HTML page. This is very similar to how we apply a regular script to a page, with a few notable differences.

First of all, you need to include type="module" <script> element, to declare this script as a module. To import the main.js script, we use this:

<script type="module" src="main.js"></script>
				

You can also embed the module's script directly into the HTML file by placing the JavaScript code within the body of the <script> element:

<script type="module">
  /* JavaScript module code here */
</script>
				

The script into which you import the module features basically acts as the top-level module. If you omit it, Firefox for example gives you an error of "SyntaxError: import declarations may only appear at top level of a module".

You can only use import and export statements inside modules, not regular scripts.

模块和标准脚本之间的其它区别

默认导出 vs 命名导出

The functionality we've exported so far has been comprised of named exports — each item (be it a function, const , etc.) has been referred to by its name upon export, and that name has been used to refer to it on import as well.

There is also a type of export called the default export — this is designed to make it easy to have a default function provided by a module, and also helps JavaScript modules to interoperate with existing CommonJS and AMD module systems (as explained nicely in ES6 In Depth: Modules by Jason Orendorff; search for "Default exports").

Let's look at an example as we explain how it works. In our basic-modules square.js you can find a function called randomSquare() that creates a square with a random color, size, and position. We want to export this as our default, so at the bottom of the file we write this:

export default randomSquare;
				

Note the lack of curly braces.

We could instead prepend export default onto the function and define it as an anonymous function, like this:

export default function(ctx) {
  ...
}
				

Over in our main.js file, we import the default function using this line:

import randomSquare from './modules/square.js';
				

Again, note the lack of curly braces. This is because there is only one default export allowed per module, and we know that randomSquare is it. The above line is basically shorthand for:

import {default as randomSquare} from './modules/square.js';
				

注意 : The as syntax for renaming exported items is explained below in the 重命名导入和导出 章节。

避免命名冲突

So far, our canvas shape drawing modules seem to be working OK. But what happens if we try to add a module that deals with drawing another shape, like a circle or triangle? These shapes would probably have associated functions like draw() , reportArea() , etc. too; if we tried to import different functions of the same name into the same top-level module file, we'd end up with conflicts and errors.

Fortunately there are a number of ways to get around this. We'll look at these in the following sections.

重命名导入和导出

Inside your import and export statement's curly braces, you can use the keyword as along with a new feature name, to change the identifying name you will use for a feature inside the top-level module.

So for example, both of the following would do the same job, albeit in a slightly different way:

// inside module.js
export {
  function1 as newFunctionName,
  function2 as anotherNewFunctionName
};
// inside main.js
import { newFunctionName, anotherNewFunctionName } from './modules/module.js';
				
// inside module.js
export { function1, function2 };
// inside main.js
import { function1 as newFunctionName,
         function2 as anotherNewFunctionName } from './modules/module.js';
				

Let's look at a real example. In our renaming directory you'll see the same module system as in the previous example, except that we've added circle.js and triangle.js modules to draw and report on circles and triangles.

Inside each of these modules, we've got features with the same names being exported, and therefore each has the same export statement at the bottom:

export { name, draw, reportArea, reportPerimeter };
				

When importing these into main.js , if we tried to use

import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
import { name, draw, reportArea, reportPerimeter } from './modules/circle.js';
import { name, draw, reportArea, reportPerimeter } from './modules/triangle.js';
				

The browser would throw an error such as "SyntaxError: redeclaration of import name" (Firefox).

Instead we need to rename the imports so that they are unique:

import { name as squareName,
         draw as drawSquare,
         reportArea as reportSquareArea,
         reportPerimeter as reportSquarePerimeter } from './modules/square.js';
import { name as circleName,
         draw as drawCircle,
         reportArea as reportCircleArea,
         reportPerimeter as reportCirclePerimeter } from './modules/circle.js';
import { name as triangleName,
        draw as drawTriangle,
        reportArea as reportTriangleArea,
        reportPerimeter as reportTrianglePerimeter } from './modules/triangle.js';
				

Note that you could solve the problem in the module files instead, e.g.

// in square.js
export { name as squareName,
         draw as drawSquare,
         reportArea as reportSquareArea,
         reportPerimeter as reportSquarePerimeter };
				
// in main.js
import { squareName, drawSquare, reportSquareArea, reportSquarePerimeter } from './modules/square.js';
				

And it would work just the same. What style you use is up to you, however it arguably makes more sense to leave your module code alone, and make the changes in the imports. This especially makes sense when you are importing from third party modules that you don't have any control over.

创建模块对象

The above method works OK, but it's a little messy and longwinded. An even better solution is to import each module's features inside a module object. The following syntax form does that:

import * as Module from './modules/module.js';
				

This grabs all the exports available inside module.js , and makes them available as members of an object 模块 , effectively giving it its own namespace. So for example:

Module.function1()
Module.function2()
etc.
				

Again, let's look at a real example. If you go to our module-objects directory, you'll see the same example again, but rewritten to take advantage of this new syntax. In the modules, the exports are all in the following simple form:

export { name, draw, reportArea, reportPerimeter };
				

The imports on the other hand look like this:

import * as Canvas from './modules/canvas.js';
import * as Square from './modules/square.js';
import * as Circle from './modules/circle.js';
import * as Triangle from './modules/triangle.js';
				

In each case, you can now access the module's imports underneath the specified object name, for example:

let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue');
Square.reportArea(square1.length, reportList);
Square.reportPerimeter(square1.length, reportList);
				

So you can now write the code just the same as before (as long as you include the object names where needed), and the imports are much neater.

模块和类

As we hinted at earlier, you can also export and import classes; this is another option for avoiding conflicts in your code, and is especially useful if you've already got your module code written in an object-oriented style.

You can see an example of our shape drawing module rewritten with ES classes in our directory. As an example, the square.js file now contains all its functionality in a single class:

class Square {
  constructor(ctx, listId, length, x, y, color) {
    ...
  }
  draw() {
    ...
  }
  ...
}
				

which we then export:

export { Square };
				

Over in main.js , we import it like this:

import { Square } from './modules/square.js';
				

And then use the class to draw our square:

let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
square1.draw();
square1.reportArea();
square1.reportPerimeter();
				

聚合模块

There will be times where you'll want to aggregate modules together. You might have multiple levels of dependencies, where you want to simplify things, combining several submodules into one parent module. This is possible using export syntax of the following forms in the parent module:

export * from 'x.js'
export { name } from 'x.js'
				

For an example, see our module-aggregation directory. In this example (based on our earlier classes example) we've got an extra module called shapes.js , which aggregates all the functionality from circle.js , square.js ,和 triangle.js together. We've also moved our submodules inside a subdirectory inside the 模块 directory called shapes . So the module structure in this example is:

modules/
  canvas.js
  shapes.js
  shapes/
    circle.js
    square.js
    triangle.js
				

In each of the submodules, the export is of the same form, e.g.

export { Square };
				

Next up comes the aggregation part. Inside shapes.js , we include the following lines:

export { Square } from './shapes/square.js';
export { Triangle } from './shapes/triangle.js';
export { Circle } from './shapes/circle.js';
				

These grab the exports from the individual submodules and effectively make them available from the shapes.js 模块。

注意 : The exports referenced in shapes.js basically get redirected through the file and don't really exist there, so you won't be able to write any useful related code inside the same file.

So now in the main.js file, we can get access to all three module classes by replacing

import { Square } from './modules/square.js';
import { Circle } from './modules/circle.js';
import { Triangle } from './modules/triangle.js';
				

采用以下单行:

import { Square, Circle, Triangle } from './modules/shapes.js';
				

动态模块加载

The newest part of the JavaScript modules functionality to be available in browsers is dynamic module loading. This allows you to dynamically load modules only when they are needed, rather than having to load everything up front. This has some obvious performance advantages; let's read on and see how it works.

This new functionality allows you to call import() as a function, passing it the path to the module as a parameter. It returns a Promise , which fulfills with a module object (see 创建模块对象 ) giving you access to that object's exports, e.g.

import('./modules/myModule.js')
  .then((module) => {
    // Do something with the module.
  });
				

Let's look at an example. In the dynamic-module-imports directory we've got another example based on our classes example. This time however we are not drawing anything on the canvas when the example loads. Instead, we include three buttons — "Circle", "Square", and "Triangle" — that, when pressed, dynamically load the required module and then use it to draw the associated shape.

In this example we've only made changes to our index.html and main.js files — the module exports remain the same as before.

Over in main.js we've grabbed a reference to each button using a Document.querySelector() call, for example:

let squareBtn = document.querySelector('.square');
				

We then attach an event listener to each button so that when pressed, the relevant module is dynamically loaded and used to draw the shape:

squareBtn.addEventListener('click', () => {
  import('./modules/square.js').then((Module) => {
    let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
    square1.draw();
    square1.reportArea();
    square1.reportPerimeter();
  })
});
				

Note that, because the promise fulfillment returns a module object, the class is then made a subfeature of the object, hence we now need to access the constructor with Module. prepended to it, e.g. Module.Square( ... ) .

故障排除

这里是可以为您提供帮助的一些技巧若模块工作时遇到麻烦。可自由添加到列表中若发现更多麻烦!

另请参阅

  1. JavaScript
  2. 教程:
  3. 完整初学者
    1. JavaScript 基础
    2. JavaScript 第一步
    3. JavaScript 构建块
    4. 引入 JavaScript 对象
  4. JavaScript 指南
    1. 介绍
    2. 语法和类型
    3. 控制流程和错误处理
    4. 循环和迭代
    5. 函数
    6. 表达式和运算符
    7. 数字和日期
    8. 文本格式
    9. 正则表达式
    10. Indexed collections
    11. Keyed collections
    12. Working with objects
    13. 对象模型的细节
    14. Using promises
    15. 迭代器和生成器
    16. Meta programming
    17. JavaScript 模块
  5. 中间体
    1. Client-side JavaScript frameworks
    2. 客户端侧 Web API
    3. 重新介绍 JavaScript
    4. JavaScript 数据结构
    5. 相等比较和相同
    6. 闭包
  6. 高级
    1. 继承和原型链
    2. 严格模式
    3. JavaScript 类型数组
    4. 内存管理
    5. 并发模型和事件循环
  7. 参考:
  8. 内置对象
    1. AggregateError
    2. Array
    3. ArrayBuffer
    4. AsyncFunction
    5. Atomics
    6. BigInt
    7. BigInt64Array
    8. BigUint64Array
    9. Boolean
    10. DataView
    11. Date
    12. Error
    13. EvalError
    14. FinalizationRegistry
    15. Float32Array
    16. Float64Array
    17. Function
    18. Generator
    19. GeneratorFunction
    20. Infinity
    21. Int16Array
    22. Int32Array
    23. Int8Array
    24. InternalError
    25. Intl
    26. JSON
    27. Map
    28. Math
    29. NaN
    30. Number
    31. Object
    32. Promise
    33. Proxy
    34. RangeError
    35. ReferenceError
    36. Reflect
    37. RegExp
    38. Set
    39. SharedArrayBuffer
    40. String
    41. Symbol
    42. SyntaxError
    43. TypeError
    44. TypedArray
    45. URIError
    46. Uint16Array
    47. Uint32Array
    48. Uint8Array
    49. Uint8ClampedArray
    50. WeakMap
    51. WeakRef
    52. WeakSet
    53. WebAssembly
    54. decodeURI()
    55. decodeURIComponent()
    56. encodeURI()
    57. encodeURIComponent()
    58. escape()
    59. eval()
    60. globalThis
    61. isFinite()
    62. isNaN()
    63. null
    64. parseFloat()
    65. parseInt()
    66. undefined
    67. unescape()
    68. uneval()
  9. 表达式 & 运算符
    1. Addition (+)
    2. Addition assignment (+=)
    3. Assignment (=)
    4. Bitwise AND (&)
    5. Bitwise AND assignment (&=)
    6. Bitwise NOT (~)
    7. Bitwise OR (|)
    8. Bitwise OR assignment (|=)
    9. Bitwise XOR (^)
    10. Bitwise XOR assignment (^=)
    11. Comma operator (,)
    12. 条件 (三元) 运算符
    13. Decrement (--)
    14. Destructuring assignment
    15. Division (/)
    16. Division assignment (/=)
    17. Equality (==)
    18. Exponentiation (**)
    19. Exponentiation assignment (**=)
    20. Function expression
    21. Greater than (>)
    22. Greater than or equal (>=)
    23. Grouping operator ( )
    24. Increment (++)
    25. Inequality (!=)
    26. Left shift (<<)
    27. Left shift assignment (<<=)
    28. Less than (<)
    29. Less than or equal (<=)
    30. Logical AND (&&)
    31. Logical AND assignment (&&=)
    32. Logical NOT (!)
    33. Logical OR (||)
    34. Logical OR assignment (||=)
    35. Logical nullish assignment (??=)
    36. Multiplication (*)
    37. Multiplication assignment (*=)
    38. Nullish coalescing operator (??)
    39. Object initializer
    40. 运算符优先级
    41. Optional chaining (?.)
    42. Pipeline operator (|>)
    43. 特性访问器
    44. Remainder (%)
    45. Remainder assignment (%=)
    46. Right shift (>>)
    47. Right shift assignment (>>=)
    48. Spread syntax (...)
    49. Strict equality (===)
    50. Strict inequality (!==)
    51. Subtraction (-)
    52. Subtraction assignment (-=)
    53. Unary negation (-)
    54. Unary plus (+)
    55. Unsigned right shift (>>>)
    56. Unsigned right shift assignment (>>>=)
    57. 异步函数表达式
    58. await
    59. class expression
    60. delete operator
    61. function* 表达式
    62. in operator
    63. instanceof
    64. new operator
    65. new.target
    66. super
    67. this
    68. typeof
    69. void 运算符
    70. yield
    71. yield*
  10. 语句 & 声明
    1. async function
    2. block
    3. break
    4. class
    5. const
    6. continue
    7. debugger
    8. do...while
    9. empty
    10. export
    11. for
    12. for await...of
    13. for...in
    14. for...of
    15. 函数声明
    16. function*
    17. if...else
    18. import
    19. import.meta
    20. label
    21. let
    22. return
    23. switch
    24. throw
    25. try...catch
    26. var
    27. while
    28. with
  11. 函数
    1. 箭头函数表达式
    2. 默认参数
    3. 方法定义
    4. 其余参数
    5. 自变量对象
    6. getter
    7. setter
    1. Private class fields
    2. Public class fields
    3. 构造函数
    4. extends
    5. static
  12. 错误
    1. Error: Permission denied to access property "x"
    2. InternalError: too much recursion
    3. RangeError: argument is not a valid code point
    4. RangeError: invalid array length
    5. RangeError: invalid date
    6. RangeError: precision is out of range
    7. RangeError: radix must be an integer
    8. RangeError: repeat count must be less than infinity
    9. RangeError: repeat count must be non-negative
    10. ReferenceError: "x" is not defined
    11. ReferenceError: assignment to undeclared variable "x"
    12. ReferenceError: can't access lexical declaration`X' before initialization
    13. ReferenceError: deprecated caller or arguments usage
    14. ReferenceError: invalid assignment left-hand side
    15. ReferenceError: reference to undefined property "x"
    16. SyntaxError: "0"-prefixed octal literals and octal escape seq. are deprecated
    17. SyntaxError: "use strict" not allowed in function with non-simple parameters
    18. SyntaxError: "x" is a reserved identifier
    19. SyntaxError: JSON.parse: bad parsing
    20. SyntaxError: Malformed formal parameter
    21. SyntaxError: Unexpected token
    22. SyntaxError: Using //@ to indicate sourceURL pragmas is deprecated. Use //# instead
    23. SyntaxError: a declaration in the head of a for-of loop can't have an initializer
    24. SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
    25. SyntaxError: for-in loop head declarations may not have initializers
    26. SyntaxError: function statement requires a name
    27. SyntaxError: identifier starts immediately after numeric literal
    28. SyntaxError: illegal character
    29. SyntaxError: invalid regular expression flag "x"
    30. SyntaxError: missing ) after argument list
    31. SyntaxError: missing ) after condition
    32. SyntaxError: missing : after property id
    33. SyntaxError: missing ; before statement
    34. SyntaxError: missing = in const declaration
    35. SyntaxError: missing ] after element list
    36. SyntaxError: missing formal parameter
    37. SyntaxError: missing name after . operator
    38. SyntaxError: missing variable name
    39. SyntaxError: missing } after function body
    40. SyntaxError: missing } after property list
    41. SyntaxError: redeclaration of formal parameter "x"
    42. SyntaxError: return not in function
    43. SyntaxError: test for equality (==) mistyped as assignment (=)?
    44. SyntaxError: unterminated string literal
    45. TypeError: "x" has no properties
    46. TypeError: "x" is (not) "y"
    47. TypeError: "x" is not a constructor
    48. TypeError: "x" is not a function
    49. TypeError: "x" is not a non-null object
    50. TypeError: "x" is read-only
    51. TypeError: 'x' is not iterable
    52. TypeError: More arguments needed
    53. TypeError: Reduce of empty array with no initial value
    54. TypeError: X.prototype.y called on incompatible type
    55. TypeError: can't access dead object
    56. TypeError: can't access property "x" of "y"
    57. TypeError: can't assign to property "x" on "y": not an object
    58. TypeError: can't define property "x": "obj" is not extensible
    59. TypeError: can't delete non-configurable array element
    60. TypeError: can't redefine non-configurable property "x"
    61. TypeError: cannot use 'in' operator to search for 'x' in 'y'
    62. TypeError: cyclic object value
    63. TypeError: invalid 'instanceof' operand 'x'
    64. TypeError: invalid Array.prototype.sort argument
    65. TypeError: invalid arguments
    66. TypeError: invalid assignment to const "x"
    67. TypeError: property "x" is non-configurable and can't be deleted
    68. TypeError: setting getter-only property "x"
    69. TypeError: variable "x" redeclares argument
    70. URIError: malformed URI sequence
    71. Warning: -file- is being assigned a //# sourceMappingURL, but already has one
    72. Warning: 08/09 is not a legal ECMA-262 octal constant
    73. Warning: Date.prototype.toLocaleFormat is deprecated
    74. Warning: JavaScript 1.6's for-each-in loops are deprecated
    75. Warning: String.x is deprecated; use String.prototype.x instead
    76. Warning: expression closures are deprecated
    77. Warning: unreachable code after return statement
  13. 杂项
    1. JavaScript technologies overview
    2. 词汇语法
    3. JavaScript 数据结构
    4. Enumerability and ownership of properties
    5. Iteration protocols
    6. 严格模式
    7. Transitioning to strict mode
    8. Template literals
    9. 弃用特征