Skip to content

es6_quick_guide

ECMAScript (ES) 是由 ECMA International 标准化的脚本语言规范。它是 JavaScript 的基础。ES6,官方名称为 ECMAScript 2015,是一个重要的更新,为该语言引入了许多新特性,使 JavaScript 更加强大和富有表现力。随后的年度版本(ES2016、ES2017 等)继续添加特性。

本教程快速概述了关键的 ES6 特性及相关的现代 JavaScript 概念。

JavaScript 于 1995 年由 Brendan Eich 在 Netscape 创建。它是一种高级的、通常采用即时编译(just-in-time compiled)的、多范式语言,遵循 ECMAScript 规范。它主要作为网页的脚本语言而闻名,但由于 Node.js,它也被用于许多非浏览器环境。

涵盖的关键 ES6 (ECMAScript 2015) 特性:

Section titled “涵盖的关键 ES6 (ECMAScript 2015) 特性:”
  • 常量 (const) 和块级作用域变量 (let)
  • 箭头函数 (Arrow Functions)
  • 默认参数值
  • 剩余参数 (Rest Parameters) 和展开语法 (Spread Syntax)
  • 模板字面量 (Template Literals)
  • 增强的对象字面量(属性简写、方法定义)
  • 解构赋值(数组和对象)
  • 模块 (import/export)
  • 类 (class 语法)
  • 迭代器 (Iterators) 和生成器 (Generators)(function*, yield)
  • 集合(Map, Set, WeakMap, WeakSet)
  • Promise(用于异步编程)
  • 各种对象(String, Array, Number, Math, Object)的新内置方法

要编写和运行 ES6+ JavaScript 代码,您有以下几种选择:

所有现代 Web 浏览器(Chrome、Firefox、Safari、Edge)对 ES6 及更高版本特性都提供了出色的支持。您可以直接在 <script> 标签中或链接到 HTML 的 .js 文件中编写 ES6 代码。浏览器开发者工具(通常按 F12 访问)提供了一个控制台,用于试验 JavaScript 和调试您的代码。

Node.js 是一个 JavaScript 运行时环境,允许您在浏览器之外运行 JavaScript 代码,通常用于服务器端应用程序、命令行工具和构建脚本。最新版本的 Node.js 对 ES6+ 特性提供了强大的支持。

访问 Node.js 官方网站 (https://nodejs.org/) 下载适用于您操作系统的安装程序(Windows、macOS、Linux)。建议安装 LTS(长期支持)版本以获得稳定性。安装通常包含 npm(Node 包管理器),用于管理项目依赖和运行脚本。

安装完成后,您可以通过打开终端或命令提示符并输入以下命令来验证:

node -v
npm -v

这将显示 Node.js 和 npm 的已安装版本。

优秀的代码编辑器或集成开发环境 (IDE) 将显著提升您的开发体验,它们提供语法高亮、代码补全、调试工具和 Git 集成等功能。流行的 JavaScript 开发工具包括:

  • Visual Studio Code (VS Code): 免费、开源、非常流行且功能丰富。提供出色的 JavaScript/TypeScript 支持和庞大的扩展市场。可在 https://code.visualstudio.com/ 获取。
  • WebStorm: JetBrains 出品的一款强大的商业 IDE,专为 JavaScript 及相关技术设计。
  • Sublime Text: 一款轻量、快速的编辑器,可通过插件扩展。
  • Atom: GitHub 构建的可定制文本编辑器,免费且开源。

如果您需要支持不完全支持 ES6+ 的旧浏览器或环境,可以使用转译器(transpiler),例如 Babel (https://babeljs.io/)。Babel 将现代 JavaScript 代码 (ES6+) 转换为更旧、兼容性更好的版本(例如 ES5)。这通常是构建过程的一部分,配合 Webpack、Parcel 或 Rollup 等工具使用。

JavaScript 语法定义了编写有效程序的规则。主要组成部分包括:

  • 变量 (Variables): 存储数据的命名容器。使用 let、const (ES6+) 或 var (旧式) 声明。
  • 字面量 (Literals): 直接写入代码的固定值(例如,100、"hello"、true、null、[1, 2]、{a:1})。
  • 运算符 (Operators): 对值执行操作的符号(例如,+、-、*、/、=、===、&&、||)。
  • 关键字 (Keywords): 具有特殊含义的保留字(例如,if、for、function、class、return、let、const)。
  • 注释 (Comments): 被解释器忽略,用于解释代码。单行注释(// ...)和多行注释(/* ... */)。
  • 标识符 (Identifiers): 变量、函数、类等的名称。规则: - 必须以字母、下划线 (_) 或美元符号 ($) 开头。 - 后续字符可以是字母、数字、下划线或美元符号。 - 区分大小写(例如,myVar 和 myvar 是不同的)。 - 不能是保留关键字。
  • 语句 (Statements): 要执行的指令。通常以分号 (;) 结尾。
  • 块 (Blocks): 用花括号 ({}) 包围的语句组。

常用 JavaScript 关键字 (ES6+ 重点):

Section titled “常用 JavaScript 关键字 (ES6+ 重点):”

break, case, catch, class, const, continue, debugger, default, delete, do, else, export, extends, false, finally, for, function, if, import, in, instanceof, let, new, null, return, super, switch, this, throw, true, try, typeof, var (legacy), void, while, with (discouraged), yield. (Note: enum, implements, interface, package, private, protected, public, static are reserved for future use, though static is used within classes.)

JavaScript 在很大程度上忽略标记之间的空白(空格、制表符、换行),允许灵活的代码格式化。但是,在某些上下文中(例如,字符串字面量内部),空白可能很重要。

分号 (;) 用于终止语句。虽然 JavaScript 有自动插入分号 (ASI) 的机制,它会尝试在缺少分号的地方插入分号,但最佳实践是明确包含分号,以避免歧义和潜在错误。

console.log("Hello ES6");
console.log("Multiple statements on one line require semicolons:"); let x = 5; let y = 10;

严格模式 ("use strict";) 是一种选择加入 JavaScript 限制变体的方式。它有助于捕获常见的编码错误,并阻止某些不安全的操作或为其抛出错误。它可以应用于整个脚本或单个函数。

"use strict";
// 严格模式下的错误示例:
// undeclaredVariable = "This would throw an error";
function strictFunction() {
"use strict";
// 函数级严格模式
// anotherUndeclared = "Error here too";
}
console.log("Strict mode is active globally in this example if at top of file.");

注意:ES6 模块默认处于严格模式。

变量是数据的命名存储。ES6 引入了 let 和 const 用于变量声明,与旧的 var 关键字相比,它们提供了更好的作用域和控制。

  • 声明一个块级作用域的局部变量,可以选择性地初始化一个值。
  • 块级作用域意味着变量只能在其定义的块 ({...}) 内部访问(例如,在 if 语句、for 循环或独立块内部)。
  • 使用 let 声明的变量不能在同一作用域内重复声明。
  • 它们会被提升 (hoisted) 到其块的顶部,但在遇到声明之前不会初始化(临时死区 - Temporal Dead Zone - TDZ)。在声明之前访问它们会导致 ReferenceError。
let count = 10;
if (count > 5) {
let message = "Greater than 5"; // 块级作用域
console.log(message);
}
// ReferenceError: message 在这里未定义
// console.log(message);
count = 20; // 允许
// SyntaxError: 标识符 'count' 已被声明
// let count = 30;
  • 声明一个块级作用域的常量。
  • 必须在声明时初始化。
  • 初始化后其值不能被重新赋值。
  • 与 let 类似,const 变量是块级作用域的,在声明之前处于 TDZ 中。
  • 对于用 const 声明的对象和数组,变量本身不能被重新赋值给新的对象/数组,但对象属性或数组元素可以被修改。
const PI = 3.14159;
// TypeError: 给常量变量赋值。
// PI = 3.14;
const person = {
name: "Alice",
age: 30
};
person.age = 31; // 允许:修改对象的属性
console.log(person);
// TypeError: 给常量变量赋值。
// person = { name: "Bob" };
  • 声明一个函数作用域或全局作用域的变量。
  • 使用 var 声明的变量会被提升 (hoisted) 到其函数或全局作用域的顶部,并初始化为 undefined。
  • 可以在同一作用域内重复声明而不会出错。

在现代 JavaScript 中,通常建议使用 let 和 const 来获得更清晰的作用域,并避免与 var 相关联的常见陷阱。

运算符 (Operators) 是对操作数(值或变量)执行操作的符号。

+ (加法), - (减法), * (乘法), / (除法), % (取模/余数), ** (指数运算符 - ES2016), ++ (自增), -- (自减)。

= (赋值), +=, -=, *=, /=, %=, **=。

== (等于,带类型强制转换), != (不等于,带类型强制转换), === (严格等于,不带类型强制转换), !== (严格不等于,不带类型强制转换), > (大于), < (小于), >= (大于或等于), <= (小于或等于)。始终优先使用 === 和 !==,而不是 == 和 !=,以避免由于类型强制转换导致的意外行为。

&& (逻辑与), || (逻辑或), ! (逻辑非)。

& (与), | (或), ^ (异或), ~ (非), << (左移), >> (有符号右移), >>> (无符号右移)。

condition ? exprIfTrue : exprIfFalse

typeof (返回操作数的类型字符串), instanceof (检查对象是否是特定类或构造函数的实例)。

展开 (...) 和剩余 (...) 运算符 (ES6):

Section titled “展开 (...) 和剩余 (...) 运算符 (ES6):”
    • 展开语法 (Spread Syntax): 将可迭代对象(如数组或字符串)展开为单独的元素,或将对象展开为键值对。用于函数调用、数组字面量和对象字面量。
    • 剩余参数 (Rest Parameter): 将不定数量的参数收集到一个数组中。用于函数参数列表。
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // 展开:[1, 2, 3, 4, 5]
function sum(...numbers) { // 剩余参数
return numbers.reduce((acc, current) => acc + current, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出: 10

决策结构允许您的代码根据条件执行不同的语句块。

如果指定的条件为真,则执行代码块。

如果条件为真,则执行一个代码块;如果条件为假,则执行另一个代码块。

顺序测试多个条件,并执行与第一个真条件对应的代码块。

let score = 85;
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 80) {
console.log("Grade: B"); // 这将执行
} else if (score >= 70) {
console.log("Grade: C");
} else {
console.log("Grade: F");
}

评估一个表达式,并将其值与一系列 case 子句进行匹配。执行与匹配的 case 相关联的语句。通常使用 break 语句退出 switch;否则,执行会继续“穿透”到后续的 case。

let day = "Monday";
switch (day) {
case "Saturday":
case "Sunday":
console.log("It's the weekend!");
break;
case "Monday":
console.log("Start of the work week.");
break;
default:
console.log("It's a weekday.");
}

循环用于重复执行代码块。

重复执行代码块已知次数。包含初始化、条件和最终表达式(增量/减量)。

for (let i = 0; i < 5; i++) {
console.log(`Iteration ${i}`);
}

只要指定的条件为真,就重复执行代码块。在每次迭代之前检查条件。

类似于 while,但在每次迭代 之后 检查条件,因此代码块总是至少执行一次。

遍历对象的可枚举字符串属性(包括继承属性)。对于数组,它遍历索引。通常不建议用于遍历数组,如果顺序很重要或者您只想遍历自身的属性;对于数组,请改用 for...of 或像 forEach 这样的数组方法。

const person = { name: "John", age: 30 };
for (const key in person) {
if (person.hasOwnProperty(key)) { // 检查自身属性的最佳实践
console.log(`${key}: ${person[key]}`);
}
}

遍历可迭代对象(如 Array, String, Map, Set 等)的值。如果您需要直接获取值,这是遍历数组元素的优选方法。

const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color);
}

循环控制语句:break(退出循环)和 continue(跳过当前迭代并继续下一次迭代)。

函数是可重用代码块,用于执行特定任务。ES6 为函数引入了多项增强。

function greet(name) {
console.log(`Hello, ${name}!`);
}
greet("World"); // Output: Hello, World!
const greet = function(name) {
return `Hello, ${name}!`;
};
console.log(greet("World")); // Output: Hello, World!

提供了一种简洁的语法来编写函数表达式。它们词法绑定了 this 值,这意味着箭头函数内部的 this 指向其外部(封闭)词法作用域的 this 值。它们不适用于需要自己 this 上下文的方法(例如引用对象本身的成员方法)或构造函数。

  • 基本形式:(param1, param2) => { statements }
  • 单个参数(括号可选):param => { statements }
  • 无参数:() => { statements }
  • 单个表达式(隐式返回,省略花括号和 return 关键字):(param1, param2) => expression
const multiply = (x, y) => x * y;
console.log(multiply(4, 5)); // 输出: 20
const square = num => num * num; // 单个参数时括号可选
console.log(square(7)); // 输出: 49
const sayHi = () => console.log("Hi there!");
sayHi(); // 输出: Hi there!
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // 输出: [2, 4, 6, 8]
function Timer() {
this.seconds = 0;
// 在传统函数中,setInterval 内部的 'this' 将是全局对象或 undefined (严格模式下)
// setInterval(function() {
// // 这里的 'this' 不是 Timer 实例
// this.seconds++;
// console.log(this.seconds);
// }, 1000);
// 箭头函数从 Timer 构造函数作用域继承 'this'
setInterval(() => {
this.seconds++;
console.log(`Timer (lexical this): ${this.seconds}`);
}, 1000);
}
// 在浏览器/Node 环境中取消注释运行此示例
// const myTimer = new Timer();

默认参数值 (Default Parameter Values) (ES6):

Section titled “默认参数值 (Default Parameter Values) (ES6):”

您可以为函数参数指定默认值。如果未提供该参数的实参或实参为 undefined,则使用默认值。

function greetUser(name = "Guest", message = "Welcome") {
console.log(`${message}, ${name}!`);
}
greetUser(); // 输出: Welcome, Guest!
greetUser("Alice"); // 输出: Welcome, Alice!
greetUser("Bob", "Good morning"); // 输出: Good morning, Bob!

剩余参数语法 (...paramName) 允许函数接受不确定数量的参数并将其作为一个数组。它必须是函数定义中的最后一个参数。

function sumAll(...numbers) {
let total = 0;
for (const num of numbers) {
total += num;
}
return total;
}
console.log(sumAll(1, 2, 3)); // 输出: 6
console.log(sumAll(10, 20, 30, 40, 50)); // 输出: 150
console.log(sumAll()); // 输出: 0

函数调用中的展开语法 (Spread Syntax) (...) (ES6):

Section titled “函数调用中的展开语法 (Spread Syntax) (...) (ES6):”

展开语法允许将可迭代对象(如数组)在函数调用中展开为单个参数。

function calculateProduct(a, b, c) {
return a * b * c;
}
const values = [2, 3, 4];
console.log(calculateProduct(...values)); // 相当于 calculateProduct(2, 3, 4) -> 输出: 24

Generator Functions (ES6): 详见专门章节。

事件是浏览器中发生的动作或情况,例如用户点击按钮、页面加载完成或按下按键。JavaScript 允许您响应这些事件。

现代且推荐的事件处理方式是使用 addEventListener() 方法。这允许您为同一事件类型向一个元素附加多个事件处理程序。

语法: element.addEventListener(type, listener, options?)

  • type: 表示事件类型的字符串(例如,"click"、"mouseover"、"keydown")。
  • listener: 当事件发生时要调用的函数(事件处理程序)。它接收一个 Event 对象作为参数。
  • options (可选): 包含选项的对象,例如 capture (boolean)、once (boolean)、passive (boolean)。
<!DOCTYPE html>
<html>
<head><title>Event Example</title></head>
<body>
<button id="myButton">Click Me</button>
<p id="message"></p>
<script>
const button = document.getElementById('myButton');
const messagePara = document.getElementById('message');
button.addEventListener('click', function(event) {
messagePara.textContent = 'Button clicked! Event type: ' + event.type;
console.log('Event object:', event);
});
button.addEventListener('mouseover', () => {
button.style.backgroundColor = 'lightblue';
});
button.addEventListener('mouseout', () => {
button.style.backgroundColor = ''; // Reset background
});
</script>
</body>
</html>
  • 鼠标事件 (Mouse Events): click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave。
  • 键盘事件 (Keyboard Events): keydown, keyup, keypress (传统方式,如果可能请避免使用)。
  • 表单事件 (Form Events): submit, reset, change (用于输入字段、选择框、文本区域), input, focus, blur。
  • 文档/窗口事件 (Document/Window Events): load, unload, DOMContentLoaded, resize, scroll。

传统事件处理(新代码中避免使用):

Section titled “传统事件处理(新代码中避免使用):”
  • HTML on-event 属性: <button onclick="myFunction()">。这混合了 HTML 和 JavaScript,使代码更难维护。

  • DOM 元素 on-event 属性: element.onclick = myFunction;。这只允许每种事件类型有一个处理程序。

当事件发生时,一个 Event 对象(或更具体的类型,如 MouseEvent、KeyboardEvent)会被传递给事件处理程序函数。该对象包含有关事件的信息,例如:

  • type: 事件的类型。
  • target: 触发事件的 DOM 元素。
  • currentTarget: 附加事件处理程序的 DOM 元素。
  • preventDefault(): 取消浏览器对该事件的默认操作的方法(例如,阻止表单提交)。
  • stopPropagation(): 阻止事件在 DOM 树中冒泡或捕获的方法。

有关 HTML5 标准事件列表,请参阅 MDN:https://developer.mozilla.org/en-US/docs/Web/Events

Cookie 是由用户的网络浏览器存储在用户计算机上的小型文本文件,用于跨会话记住有关用户的信息。JavaScript 可以使用 document.cookie 与 Cookie 交互。

关键操作:

  • 设置/更新: document.cookie = "name=value; expires=UTCString; path=/; SameSite=Lax";
  • 读取: document.cookie 返回所有 Cookie 的字符串;您需要解析它。
  • 删除: 将 expires 属性设置为一个过去日期。

重要:对 Cookie 值始终使用 encodeURIComponent(),读取时使用 decodeURIComponent()。出于安全考虑,考虑 HttpOnly、Secure 和 SameSite 属性(通常在服务器端设置)。对于不需要服务器交互的客户端存储,localStorage 和 sessionStorage 通常是更好的替代方案。

详见专门的“ES6 - Cookies”章节以获取详细示例和最佳实践。

JavaScript 可以使用 window.location 对象将浏览器重定向到新的 URL。

  • window.location.href = "new_url"; (导航并添加到历史记录)
  • window.location.assign("new_url"); (与上述相同)
  • window.location.replace("new_url"); (导航但替换历史记录中的当前条目,后退按钮不会返回到原始页面)
  • window.location.reload(); (重新加载当前页面)

对于 SEO,服务器端重定向(永久重定向使用 301)通常优于 JavaScript 重定向。

详见专门的“ES6 - 页面重定向”章节以获取更多详细信息。

JavaScript 提供了内置函数,通过对话框进行简单的用户交互。尽管它们功能可用,但它们是模态的(阻塞用户与页面其余部分的交互),并且外观通常比较过时。现代 Web 应用程序通常使用自定义风格的模态框或通知。

显示带有一个“确定”按钮的简单消息。

显示带有一个“确定”按钮和一个“取消”按钮的消息。如果点击“确定”返回 true,如果点击“取消”返回 false。

显示消息询问用户输入,带有一个输入字段。如果点击“确定”返回输入的字符串,如果点击“取消”返回 null。defaultValue 是输入字段的可选初始值。

alert("This is an alert!");
const wantsToContinue = confirm("Do you want to continue?");
if (wantsToContinue) {
console.log("User wants to continue.");
} else {
console.log("User does not want to continue.");
}
const userName = prompt("Please enter your name:", "John Doe");
if (userName !== null) {
console.log(`Hello, ${userName}`);
} else {
console.log("User cancelled the prompt.");
}

void 运算符评估一个表达式然后返回 undefined。它在过去的主要用途是与 javascript: URL 结合使用,以防止当表达式的返回值可能导致浏览器离开当前页面时进行导航。

语法: void expression 或 void(expression)

<a href="javascript:void(0);">Do nothing link</a>
<a href="javascript:void(console.log('Clicked!'));">Log and do nothing link</a>

在现代 JavaScript 中,void 0 有时被用作获取 undefined 值的简洁方式。然而,简单地使用 undefined 基本类型通常更清晰。随着现代事件处理(例如,event.preventDefault())的出现,javascript:void(0) 在链接中的需求已经减少。

JavaScript 可以使用 window.print() 方法触发浏览器的打印对话框。这将尝试打印当前文档。

<!DOCTYPE html>
<html>
<head><title>Print Example</title></head>
<body>
<p>This is some content to print.</p>
<button onclick="window.print()">Print this page</button>
</body>
</html>

您可以使用 CSS 媒体查询 (@media print) 为页面的打印版本定义特定的样式,使其与屏幕版本不同。

对象是键值对(属性)的集合。ES6 引入了多项增强功能以处理对象。

  • 属性简写 (Shorthand Property Names): 如果变量名与属性键相同,您可以省略冒号和值:let name = "Alice"; let person = { name }; 等同于 let person = { name: name };
  • 方法简写 (Shorthand Method Names): let person = { greet() { console.log("Hello"); } }; 代替 let person = { greet: function() { console.log("Hello"); } };
  • 计算属性名 (Computed Property Names): 在对象字面量中使用方括号内的表达式作为属性键:let propName = "age"; let person = { [propName]: 30 };

将一个或多个源对象中所有可枚举的自身属性复制到目标对象(浅拷贝)。用于合并对象或克隆。

对象解构 (Object Destructuring):详见专门章节。

详见专门的“ES6 - 对象”章节以获取更多详细信息和示例。

ES6 为 Number 对象添加了新的属性和方法。

  • Number.EPSILON: 两个可表示数字之间最小的间隔。
  • Number.isFinite(value): 检查值是否为有限数字。
  • Number.isInteger(value): 检查值是否为整数。
  • Number.isNaN(value): 检查值是否为 NaN(比全局 isNaN() 更健壮)。
  • Number.isSafeInteger(value): 检查值是否为安全整数(可以精确表示为 IEEE-754 双精度数)。
  • Number.parseFloat(string) 和 Number.parseInt(string, radix): 全局函数也可在 Number 对象上使用。

二进制数使用前缀 0b 或 0B(例如,0b1010 是 10)。 八进制数使用前缀 0o 或 0O(例如,0o12 是 10)。

Boolean 对象表示真假值:true 或 false。JavaScript 中隐式为假(falsy 值)的值包括 false、0、-0、0n (BigInt 零)、"" (空字符串)、null、undefined 和 NaN。所有其他值都是真值 (truthy)。

字符串表示文本数据。ES6 引入了模板字面量和新的字符串方法。

模板字面量 (Template Literals): Hello, ${name}! 用于轻松实现字符串插值和多行字符串。

新方法:startsWith()、endsWith()、includes()、repeat()。

详见专门的“ES6 - Strings”和“ES6 - 新字符串方法”章节。

数组是有序的值集合。ES6 为数组添加了许多有用的方法和特性。

  • Array.from(arrayLikeOrIterable, mapFn?, thisArg?): 从类数组对象或可迭代对象创建一个新的 Array 实例。
  • Array.of(...elements): 创建一个新的 Array 实例,参数数量可变,无论参数的数量或类型如何。
  • find(callbackFn, thisArg?): 返回满足所提供测试函数的第一个元素。
  • findIndex(callbackFn, thisArg?): 返回满足所提供测试函数的第一个元素的索引。
  • fill(value, start?, end?): 用静态值填充数组从开始索引到结束索引之间的所有元素。
  • copyWithin(target, start?, end?): 将数组的一部分浅拷贝到同一数组中的另一个位置。
  • entries(): 返回一个新的 Array 迭代器对象,其中包含每个索引的键/值对。
  • keys(): 返回一个新的 Array 迭代器对象,其中包含每个索引的键(索引)。
  • values(): 返回一个新的 Array 迭代器对象,其中包含每个索引的值。

展开语法 (...) 和解构:与数组一起使用也非常有用。

Date 对象用于处理日期和时间。它的 API 在 ES6 中基本没有变化,但对于日期操作很重要。由于原生 Date 对象处理时区和格式化比较复杂,现代 JavaScript 通常使用 date-fns 或 Luxon 等库来提供更健壮和开发人员友好的日期/时间处理能力。

Math 对象提供了数学常数和函数的属性和方法。ES6 添加了几个新的辅助方法:

  • Math.trunc(x): 通过移除小数部分返回 x 的整数部分。
  • Math.sign(x): 返回 x 的符号(正数返回 1,负数返回 -1,零返回 0)。
  • Math.cbrt(x): 返回 x 的立方根。
  • Math.log2(x): 返回 x 的以 2 为底的对数。
  • Math.log10(x): 返回 x 的以 10 为底的对数。
  • Math.log1p(x): 返回 1 + x 的自然对数。
  • Math.expm1(x): 返回 e^x - 1。
  • Math.cosh(x), Math.sinh(x), Math.tanh(x), Math.acosh(x), Math.asinh(x), Math.atanh(x): 双曲函数。
  • Math.hypot(...values): 返回其参数的平方和的平方根。
  • Math.clz32(x): 返回 x 的 32 位二进制表示中前导零的个数。

正则表达式 (RegExp) 是用于在字符串中匹配字符组合的模式。ES6 引入了新的标志和特性:

  • y (sticky) 标志: 只从 RegExp 对象的 lastIndex 属性指示的索引开始匹配。匹配必须从 lastIndex 开始。
  • u (unicode) 标志: 启用更全面的 Unicode 支持,包括正确匹配基本多文种平面 (BMP) 之外的字符以及处理 Unicode 属性转义序列(\p{...})。
  • RegExp 构造函数可以接受另一个 RegExp 对象作为参数: new RegExp(/abc/ig, 'i') 创建一个具有可能不同标志的新 RegExp 对象。

文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口。它将页面结构表示为对象树,允许 JavaScript 动态访问和更新网页的内容、结构和样式。

  • 节点 (Nodes): HTML 文档中的一切都是一个节点(元素节点、文本节点、属性节点、注释节点)。
  • document 对象: DOM 的入口点,表示整个 HTML 文档。
  • 选择元素: - document.getElementById('id') - document.getElementsByTagName('tagname') (返回 HTMLCollection) - document.getElementsByClassName('classname') (返回 HTMLCollection) - document.querySelector('cssSelector') (返回第一个匹配的元素) - document.querySelectorAll('cssSelector') (返回所有匹配元素的 NodeList)
  • 操作元素: - 读取/修改内容:element.innerHTML、element.textContent、element.value(用于表单元素)。 - 修改属性:element.getAttribute()、element.setAttribute()、element.removeAttribute()、直接属性访问(例如,element.id、element.className)。 - 修改样式:element.style.property(例如,element.style.color = 'blue')、element.classList(add、remove、toggle、contains)。
  • 创建和添加元素: - document.createElement('tagname') - parentNode.appendChild(newNode) - parentNode.insertBefore(newNode, referenceNode) - element.remove() (ES6+)
  • 遍历 DOM: parentNode、childNodes、firstChild、lastChild、nextSibling、previousSibling、parentElement、children、firstElementChild、lastElementChild、nextElementSibling、previousElementSibling。

加载页面后,避免使用过时的方法(如 document.write())来修改内容。

ES6 引入了新的内置可迭代数据结构:Map、Set、WeakMap 和 WeakSet。

有序的键值对集合。键可以是任何值(包括对象和基本类型)。方法:set(key, value)、get(key)、has(key)、delete(key)、clear()、size 属性。可通过 keys()、values()、entries() 进行迭代。

有序的唯一值集合。值可以是任何类型。方法:add(value)、has(value)、delete(value)、clear()、size 属性。可通过 keys()、values()、entries() 进行迭代(对于 Set,键和值相同)。

特殊版本,其中键(对于 WeakMap)或值(对于 WeakSet)必须是对象。它们持有“弱”引用,这意味着如果一个对象键/值是仅剩的引用,它可以被垃圾回收。它们不可迭代,也没有 size 属性。用于将数据与对象关联,而不会阻止其垃圾回收。

ES6 引入了 class 语法,它主要是 JavaScript 现有基于原型的继承的语法糖。它提供了一种更清晰、更熟悉的方式来创建对象和实现继承。

  • class 关键字: class MyClass { ... }
  • constructor 方法: 用于创建和初始化类创建的对象的特殊方法。一个类只能有一个构造函数。
  • 方法 (Methods): 在类中定义的函数。
  • static 方法: 在类本身上调用,而不是在实例上调用。static myStaticMethod() { ... }
  • extends 关键字: 用于继承。class ChildClass extends ParentClass { ... }
  • super 关键字: 用于调用父类的构造函数(super())或方法(super.parentMethod())。
  • Getter 和 Setter: get myProp() { ... },set myProp(value) { ... }
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
super.speak(); // 调用父类方法
console.log(`${this.name} barks.`);
}
}
const myDog = new Dog("Rex", "German Shepherd");
myDog.speak();
// 输出:
// Rex makes a noise.
// Rex barks.

Promise 是代表异步操作最终完成(或失败)及其结果值的对象。与传统的回调函数相比,它们提供了一种更清晰的方式来处理异步代码,避免了“回调地狱”。

Promise 可以处于以下三种状态之一:

Section titled “Promise 可以处于以下三种状态之一:”
  • Pending (挂起): 初始状态,既未完成也未拒绝。
  • Fulfilled (已完成/已解决): 操作成功完成,带有结果值。
  • Rejected (已拒绝): 操作失败,带有原因(错误)。
const myPromise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true; // 或 false
if (success) {
resolve("Operation successful!");
} else {
reject(new Error("Operation failed."));
}
}, 1000);
});

使用 .then() 处理完成,.catch() 处理拒绝,.finally() 处理无论结果如何都会运行的代码。

myPromise
.then(result => {
console.log("Success:", result);
})
.catch(error => {
console.error("Error:", error.message);
})
.finally(() => {
console.log("Promise settled.");
});

async 函数和 await 关键字构建在 Promise 之上,提供了一种看起来更像同步的方式来编写异步代码。

async function fetchData() {
try {
console.log("Fetching data...");
const result = await myPromise; // 暂停执行直到 myPromise 完成
console.log("Data received:", result);
return result;
} catch (error) {
console.error("Fetch error:", error.message);
throw error; // 如果需要则重新抛出
}
}
fetchData().then(data => console.log("Final result from async function:", data));

ES6 引入了 JavaScript 的标准化模块系统,允许将代码组织成可重用的部分。模块有助于管理依赖关系并创建更易于维护的应用程序。

导出 (Exporting): 使用 export 关键字使函数、变量或类可以从模块中被访问。

lib.js
export const PI = 3.14159;
export function greet(name) {
return `Hello, ${name}`;
}
export default function multiply(a, b) { // 默认导出
return a * b;
}

导入 (Importing): 使用 import 关键字在另一个模块中使用导出的成员。

main.js
import multiply, { PI, greet } from './lib.js'; // 先默认导入,然后命名导入
// import * as utils from './lib.js'; // 以命名空间方式导入所有内容
console.log(PI); // 3.14159
console.log(greet("ES6 Modules")); // Hello, ES6 Modules
console.log(multiply(5, 2)); // 10

ES6 模块通常通过 <script type="module" src="..."></script> 在浏览器中使用。Node.js 也支持 ES 模块(通常需要 .mjs 扩展名或特定的 package.json 配置)。对于旧环境,Babel 等转译器会将 ES 模块转换为其他格式(如 CommonJS 或 AMD)。

适当的错误处理对于健壮的应用程序至关重要。JavaScript 使用 try...catch...finally 块进行同步错误处理,而 Promise 具有内置机制(.catch(),async/await 结合 try/catch)处理异步错误。

try 块包含可能抛出错误的代码。如果发生错误,将执行 catch 块,并带有一个错误对象。finally 块(可选)无论是否发生错误都会执行。

try {
let result = riskyOperation();
console.log(result);
} catch (error) {
console.error("An error occurred:", error.name, error.message);
// error.stack 对于调试也很有用
} finally {
console.log("Cleanup code runs here.");
}

throw 语句:用于创建和抛出自定义错误或重新抛出现有错误。throw new Error("Something went wrong");

错误对象:标准内置错误类型包括 Error, SyntaxError, TypeError, RangeError, ReferenceError, URIError。您可以通过扩展 Error 创建自定义错误类。

详见专门的“ES6 - 错误处理”章节以获取更多详细信息。

表单验证确保用户输入在处理或提交之前是正确、完整且格式正确的。验证可以发生在客户端(在浏览器中使用 JavaScript)和/或服务器端。

  • 改善用户体验: 为用户提供即时反馈,减少沮丧感。
  • 减少服务器负载: 防止因无效数据而产生不必要的请求。
  • HTML5 内置验证: 在表单元素上使用 required、type(例如,email、number、url)、pattern(用于正则表达式)、min、max、minlength、maxlength 等属性。浏览器会处理基本验证并提供默认错误消息。
  • JavaScript 验证: 用于更复杂或自定义的验证逻辑。访问表单字段值,根据规则检查它们,并显示自定义错误消息。通常与 HTML5 验证结合使用。
<!DOCTYPE html>
<html>
<head><title>Validation</title></head>
<body>
<form id="myForm">
<label for="email">Email:</label>
<input type="text" id="email" name="email">
<span id="emailError" style="color:red;"></span><br><br>
<button type="submit">Submit</button>
</form>
<script>
const form = document.getElementById('myForm');
const emailInput = document.getElementById('email');
const emailError = document.getElementById('emailError');
form.addEventListener('submit', function(event) {
event.preventDefault(); // 阻止默认的表单提交
validateEmail();
});
function validateEmail() {
const emailValue = emailInput.value.trim();
if (emailValue === '') {
emailError.textContent = 'Email is required.';
return false;
} else if (!/^\S+@\S+\.\S+$/.test(emailValue)) { // 简单的邮箱正则表达式
emailError.textContent = 'Please enter a valid email address.';
return false;
}
emailError.textContent = ''; // 清除错误
// 如果有效,您可以继续表单提交(例如,使用 Fetch API)
console.log('Form submitted with email:', emailValue);
return true;
}
</script>
</body>
</html>

重要: 始终也实现服务器端验证,因为客户端验证可以被绕过。

JavaScript 可以通过随时间动态改变元素的属性(如位置、大小、颜色、不透明度)来创建网页上的动画。

这是在 JavaScript 中创建平滑高效动画的现代、推荐方式。浏览器在下一次屏幕重绘之前(通常每秒 60 次)调用您的 callback 函数。这使得动画与浏览器的刷新率同步,与使用 setTimeout 或 setInterval 进行动画相比,性能更好,卡顿更少。

requestAnimationFrame 移动元素的示例:

Section titled “requestAnimationFrame 移动元素的示例:”
<!DOCTYPE html>
<html>
<head>
<title>Animation</title>
<style> #box { width: 50px; height: 50px; background-color: blue; position: relative; } </style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let position = 0;
let startTime = null;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
const progress = timestamp - startTime;
position += 1; // 每帧移动 1 像素
if (position > 300) position = 0; // 重置位置
box.style.left = position + 'px';
if (progress < 5000) { // 运行动画约 5 秒
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate); // 启动动画
</script>
</body>
</html>

使用 setTimeout / setInterval 的传统动画(旧代码):

Section titled “使用 setTimeout / setInterval 的传统动画(旧代码):”

虽然可能,但使用 setTimeout 或 setInterval 进行动画可能导致卡顿和效率低下,因为它们与浏览器的重绘周期不同步。requestAnimationFrame 通常更优越。

对于许多常见的动画(例如,悬停效果、状态之间的过渡),CSS 动画和 CSS 过渡通常是更好的选择。浏览器可以优化它们,因此它们通常性能更好,并且将表现逻辑与 JavaScript 分离。

现代 Web 浏览器主要通过 HTML5 的 <audio> 和 <video> 元素支持多媒体内容。JavaScript 提供了 API 来控制这些元素。

这些元素允许您直接将音频和视频内容嵌入到网页中。它们具有 src、controls、autoplay、loop、muted、poster(用于视频)等属性。

<video id="myVideo" width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
您的浏览器不支持 video 标签。
</video>
<audio id="myAudio" controls>
<source src="sound.mp3" type="audio/mpeg">
<source src="sound.ogg" type="audio/ogg">
您的浏览器不支持 audio 元素。
</audio>

您可以使用音频/视频 DOM 元素上的 JavaScript 方法和属性来控制播放、音量、音轨选择等:

  • 方法: play()、pause()、load()。
  • 属性: currentTime、duration、volume、muted、paused、ended、src。
  • 事件: play、pause、ended、timeupdate、volumechange、canplay、error。
<!DOCTYPE html><html><head><title>Media Control</title></head><body>
<video id="sampleVideo" width="320" height="240" src="your_video.mp4"></video><br>
<button onclick="document.getElementById('sampleVideo').play()">Play</button>
<button onclick="document.getElementById('sampleVideo').pause()">Pause</button>
<input type="range" min="0" max="1" step="0.1" value="1"
oninput="document.getElementById('sampleVideo').volume = this.value">
音量
</body></html>

之前用于检测浏览器插件(如 Flash)的 navigator.plugins 和 navigator.mimeTypes 对象已基本过时,因为现代 Web 依赖于浏览器内置的多媒体功能。

调试是查找和修复代码中错误(bug)的过程。现代浏览器和 Node.js 提供了强大的调试工具。

所有主流浏览器都包含开发者工具(通常按 F12 或右键点击 -> 检查 打开)。JavaScript 调试的主要功能:

  • 控制台 (Console): 查看 console.log() 消息、错误和警告。交互式执行 JavaScript 表达式。
  • 调试器/源文件面板 (Debugger/Sources Panel): 在代码中设置断点以暂停执行。逐行单步执行代码(step over、step into、step out)。检查变量值、调用堆栈和作用域链。
  • 网络面板 (Network Panel): 检查网络请求和响应。
  • 性能面板 (Performance Panel): 分析 JavaScript 执行以识别瓶颈。
  • console.log(...data): 常规输出。
  • console.error(...data): 输出错误消息。
  • console.warn(...data): 输出警告消息。
  • console.info(...data): 输出信息性消息。
  • console.table(data): 将表格数据以表格形式显示。
  • console.group(label) / console.groupEnd(): 分组相关的日志消息。
  • console.time(label) / console.timeEnd(label): 测量执行时间。

在代码中放置 debugger; 语句将像一个断点一样工作,如果开发者工具打开,会在该行暂停执行。

  • 内置调试器: node inspect myscript.js(或 node --inspect myscript.js 用于集成 Chrome DevTools)。
  • IDE 调试器: VS Code 和其他 IDE 针对 Node.js 应用程序提供了出色的内置调试器。
  • 理解错误: 仔细阅读错误消息;它们通常指向问题的发生位置和类型。
  • 持续复现 bug: 确定触发 bug 的步骤。
  • 隔离问题: 简化代码或注释掉部分代码,以缩小 bug 发生的范围。
  • 策略性地使用 console.log: 在不同阶段打印变量值,以了解代码流程和状态。
  • 使用断点和单步执行代码: 详细观察执行流程和变量变化。

客户端图像映射允许您在图像中定义可点击区域(热点),其中每个区域可以链接到不同的 URL 或触发 JavaScript 函数。

  • <img usemap="#mapname">: <img> 标签包含 usemap 属性,指向 <map> 元素的 name。
  • <map name="mapname">: 此元素包含可点击区域的定义。
  • <area shape="rect|circle|poly" coords="..." href="url" alt="text">: 定义一个可点击区域。 - shape: rect (矩形), circle (圆形), 或 poly (多边形)。 - coords: 定义形状的坐标。(例如,x1,y1,x2,y2 用于 rect;x,y,radius 用于 circle;x1,y1,x2,y2,...,xn,yn 用于 poly)。 - href: 要导航到的 URL。 - alt: 区域的替代文本。

您可以将 JavaScript 事件处理程序(如 onclick、onmouseover)附加到 <area> 元素上,以便执行操作,而不是或除了导航到 URL 之外。

<!DOCTYPE html>
<html>
<head><title>Image Map</title>
<script>
function showRegion(regionName) {
document.getElementById('regionInfo').textContent = '您悬停在:' + regionName;
}
function clearRegion() {
document.getElementById('regionInfo').textContent = '';
}
</script>
</head>
<body>
<img src="your-image.jpg" alt="Sample Image Map" usemap="#samplemap" width="300" height="200">
<map name="samplemap">
<area shape="rect" coords="0,0,100,100" href="#" alt="Top-Left Quadrant"
onmouseover="showRegion('Top-Left Quadrant')" onmouseout="clearRegion()"
onclick="alert('Clicked Top-Left'); return false;">
<area shape="circle" coords="200,100,50" href="#" alt="Center-Right Circle"
onmouseover="showRegion('Center-Right Circle')" onmouseout="clearRegion()"
onclick="alert('Clicked Center-Right'); return false;">
</map>
<p id="regionInfo"></p>
</body>
</html>

虽然仍然受支持,但如今图像映射在复杂 UI 中不太常见。CSS 技术、SVG 或基于 JavaScript 的 Canvas 命中检测可能为交互式图形提供更大的灵活性。然而,对于静态图像上简单的链接区域,它们仍然是一个有效的选择。

理解浏览器环境对于 Web 开发非常重要。JavaScript 中的 navigator 对象提供了有关浏览器及其能力的信息。

  • navigator.userAgent: 一个字符串,包含浏览器发送到服务器的用户代理头部信息。此字符串通常包括浏览器名称、版本、操作系统和渲染引擎详细信息。注意: 通常不鼓励使用用户代理嗅探来进行特性检测,因为它不可靠且难以维护。优先使用特性检测。
  • navigator.language / navigator.languages: 关于用户首选语言的信息。
  • navigator.platform: (已废弃) 表示浏览器运行平台的字符串(例如,“Win32”,“MacIntel”)。
  • navigator.cookieEnabled: 一个布尔值,指示浏览器中是否启用 Cookie。
  • navigator.onLine: 一个布尔值,指示浏览器当前是否具有网络连接。
  • navigator.javaEnabled(): (已基本过时) 检查 Java(不是 JavaScript)是否启用。
  • navigator.sendBeacon(url, data?): 将少量 HTTP 数据从浏览器异步传输到 Web 服务器,对于分析或诊断非常有用,且不会延迟页面卸载。

特性检测 (Feature Detection) vs. 浏览器嗅探 (Browser Sniffing):

Section titled “特性检测 (Feature Detection) vs. 浏览器嗅探 (Browser Sniffing):”

与其尝试识别特定浏览器(navigator.userAgent 嗅探),几乎总是最好检测您想要使用的特定特性是否受支持。

if (typeof Promise !== "undefined") {
console.log("支持 Promise。");
} else {
console.log("不支持 Promise。请考虑使用 polyfill。");
}
if ('geolocation' in navigator) {
console.log("Geolocation API 可用。");
navigator.geolocation.getCurrentPosition(pos => console.log(pos.coords));
} else {
console.log("Geolocation API 不可用。");
}

现代浏览器高度符合标准,减少了对大量特定浏览器代码的需求。然而,理解浏览器差异对于性能优化、处理特定浏览器 bug 或使用非常新的特性仍然很重要。