ES6 是 ECMAScript 6 的简称,也称为 ECMAScript 2015(ES2015)。它是 JavaScript 语言的重大更新,引入了许多现代语法特性和功能。
[Let 变量定义](#Let 变量定义)
[Map 和 Reduce](#Map 和 Reduce)
Let 变量定义
在 ES6 之前,JavaScript 只有 var 来定义变量,它存在 变量提升 和 函数作用域 的问题。let 解决了这些问题,它拥有 块级作用域。
-
块级作用域:
let声明的变量只在它所在的代码块(例如if语句块、for循环块或{}内部)内有效。 -
无变量提升: 必须先声明再使用。
javascript
function exampleLet() {
var x = 1;
let y = 2;
if (true) {
var x = 3; // 覆盖了函数作用域的 x
let y = 4; // 这是一个新的块级作用域的 y
console.log(y); // 输出: 4
}
console.log(x); // 输出: 3 (因为 var 发生了变量提升/覆盖)
console.log(y); // 输出: 2 (因为 let 有块级作用域)
}
exampleLet();
// const 也是块级作用域,用于定义常量(不可重新赋值)
const PI = 3.14159;
// PI = 3.14; // 会报错:Assignment to constant variable.
结构表达式
结构表达式 (或称解构赋值)允许您从数组或对象中提取数据,并将它们赋值给独立的变量,语法更简洁。
数组解构
javascript
// 数组解构
const colors = ['Red', 'Green', 'Blue'];
const [first, second, third] = colors;
console.log(first); // 输出: Red
console.log(second); // 输出: Green
// 也可以跳过某些元素
const [,, last] = colors;
console.log(last); // 输出: Blue
对象解构
javascript
// 对象解构
const person = { name: 'Alice', age: 30 };
const { name, age } = person;
console.log(name); // 输出: Alice
console.log(age); // 输出: 30
// 也可以在解构时重命名变量
const { name: userName, age: userAge } = person;
console.log(userName); // 输出: Alice
console.log(userAge); // 输出: 30
函数优化
箭头函数 (=>) 提供了一种更简洁的函数写法,并且改变了函数内部 this 的绑定方式。
-
简洁语法: 当只有一个参数时,可以省略括号;当函数体只有一条
return语句时,可以省略return关键字和大括号。 -
this绑定: 箭头函数没有自己的this,它会捕获其定义时所处的外层(词法)作用域 的this值。
javascript
// 传统函数
const addOld = function(a, b) {
return a + b;
};
// 箭头函数 (标准写法)
const add = (a, b) => {
return a + b;
};
// 箭头函数 (简洁写法 - 省略 return 和大括号)
const multiply = (a, b) => a * b;
console.log(add(1, 2)); // 输出: 3
console.log(multiply(3, 4)); // 输出: 12
// 只有一个参数时可以省略参数的括号
const square = num => num * num;
console.log(square(5)); // 输出: 25
对象优化
ES6 引入了对象字面量(Object Literals)的增强,让对象创建更方便。主要包括:
-
属性名简写 (Shorthand Property Names): 如果对象属性名与变量名相同,可以直接简写。
-
方法简写 (Shorthand Method Names): 定义方法时可以省略
function关键字。
javascript
const name = 'Bob';
const age = 25;
// ES5 写法
/*
const userES5 = {
name: name,
age: age,
greet: function() {
console.log('Hello, ' + this.name);
}
};
*/
// ES6 增强对象字面量写法
const userES6 = {
name, // 属性名简写
age, // 属性名简写
greet() { // 方法简写 (省略 function)
console.log(`Hello, ${this.name}!`); // 结合了模板字符串
}
};
console.log(userES6.name); // 输出: Bob
userES6.greet(); // 输出: Hello, Bob!
Map 和 Reduce
Map 和 Reduce 是 数组原型 上新增的两个非常常用的高阶函数(High-Order Functions),它们用于对数组进行高效且简洁的处理。
-
Array.prototype.map(): 对数组的每个元素 执行一次回调函数,并用执行结果构造一个新数组。 -
Array.prototype.reduce(): 对数组中的所有元素执行一个累加器函数,将其归并为单个返回值。
javascript
const numbers = [1, 2, 3, 4];
// Map 案例:将数组中的每个数字乘以 2
const doubled = numbers.map(num => num * 2);
console.log(doubled); // 输出: [2, 4, 6, 8]
// Reduce 案例:计算数组中所有元素的总和
// 0 是初始值 (accumulator 的初始值)
const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
console.log(sum); // 输出: 10 (1 + 2 + 3 + 4)
promise
Promise (承诺)是处理 异步操作 的一种方式,旨在解决传统回调函数(Callback)导致的"回调地狱"(Callback Hell)问题,使异步代码更易于编写、阅读和管理。
一个 Promise 有三种状态:
-
Pending (进行中): 初始状态。
-
Fulfilled (已成功): 操作成功完成。
-
Rejected (已失败): 操作失败。
javascript
function delay(ms) {
// 返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
// 模拟一个异步操作(例如网络请求)
setTimeout(() => {
// 假设成功,调用 resolve 并传递结果
if (ms > 100) {
resolve(`延迟了 ${ms} 毫秒!`);
} else {
// 假设失败,调用 reject 并传递错误
reject('延迟时间太短了!');
}
}, ms);
});
}
// 使用 Promise
delay(1000)
.then(result => {
// 操作成功时执行
console.log(result); // 输出: 延迟了 1000 毫秒!
return '下一步操作'; // 可以链式调用
})
.then(nextResult => {
console.log(nextResult); // 输出: 下一步操作
return delay(50); // 尝试一个失败的 Promise
})
.catch(error => {
// 链中任何一个 Promise 失败时执行
console.log('捕获到错误:', error); // 输出: 捕获到错误: 延迟时间太短了!
});
模块化
ES6 引入了原生的 模块系统 ,允许您将代码分割成可重用的文件(模块),并通过标准化的 import 和 export 语法来共享功能。
-
export: 用于从模块中导出变量、函数或类。 -
import: 用于在其他文件中导入模块导出的内容。
导出 (在 math.js 文件中)
javascript
// 命名导出 (Named Exports)
export const PI = 3.14;
// 命名导出
export function add(a, b) {
return a + b;
}
// 默认导出 (Default Export) - 每个模块只能有一个
const subtract = (a, b) => a - b;
export default subtract;
导入 (在 main.js 文件中)
javascript
// 导入命名导出,需要使用相同的名称并加大括号
import { PI, add } from './math.js';
// 导入默认导出,可以使用任何名称 (这里的 sub 是指默认导出的 subtract 函数)
import sub from './math.js';
console.log(PI); // 输出: 3.14
console.log(add(5, 3)); // 输出: 8
console.log(sub(5, 3)); // 输出: 2
// 也可以将所有命名导出导入为一个对象
import * as MathUtils from './math.js';
console.log(MathUtils.add(10, 5)); // 输出: 15
上面七部分的整体示例
es6_demo.html:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>ES6 核心特性演示</title>
</head>
<body>
<h1>请打开浏览器的控制台 (Console) 查看 ES6 示例输出</h1>
<script type="module">
// -------------------------------------------------------------------------------------------------------
// 由于浏览器的模块系统 (ES Modules) 需要单独的文件才能使用 import/export,
// 我们将 1.7 模块化相关的代码拆分到 math.js 中,并在下面进行导入。
// 请注意:您需要将 math.js 文件和这个 HTML 文件放在同一个文件夹下。
// -------------------------------------------------------------------------------------------------------
// 1.7.1 导出 (请创建 math.js 文件)
// const mathJsContent = `
// export const PI = 3.14;
// export function add(a, b) {
// return a + b;
// }
// const subtract = (a, b) => a - b;
// export default subtract;
// `;
// 提示:在实际操作中,您需要手动创建 math.js 文件并粘贴上述内容。
// -------------------------------------------------------------------------------------------------------
// 1.7 模块化 (import)
// 导入命名导出和默认导出
import { PI, add } from './math.js';
import sub from './math.js';
console.log("--- 1. ES6 核心特性整合演示 ---");
// --- 1.1 Let 和 Const 变量定义 (块级作用域) ---
console.log("\n--- 1.1 Let/Const (块级作用域) ---");
let outerVar = "外部";
const OUTER_CONST = 100;
if (true) {
let outerVar = "内部"; // 块级作用域,不影响外部
console.log("内部作用域的 outerVar:", outerVar); // 输出: 内部
}
// for 循环中的 let 每次迭代都会创建新的变量,对 Promise, setTimeout 等异步操作尤其重要
console.log("外部作用域的 outerVar:", outerVar); // 输出: 外部
// console.log(OUTER_CONST = 101); // 尝试修改 const 会报错
// --- 1.2 结构表达式 (Destructuring) ---
console.log("\n--- 1.2 结构表达式 ---");
const user = { firstName: 'Leo', role: 'Engineer', city: 'Shanghai' };
const data = [10, 20, 30];
// 对象解构 (并重命名)
const { firstName: uName, role, country = 'China' } = user;
console.log(`姓名: ${uName}, 角色: ${role}, 国家(默认值): ${country}`);
// 数组解构 (并跳过元素)
const [firstNum, , thirdNum] = data;
console.log(`数组的首项: ${firstNum}, 数组的第三项: ${thirdNum}`);
// --- 1.3 函数优化 (箭头函数) ---
console.log("\n--- 1.3 箭头函数 ---");
// 简洁语法
const calculateArea = (width, height) => width * height;
console.log("面积:", calculateArea(5, 8)); // 输出: 40
// --- 1.4 对象优化 (增强对象字面量) ---
console.log("\n--- 1.4 增强对象字面量 ---");
const a = 1, b = 2;
const myObject = {
a, // 属性名简写 (a: a)
b, // 属性名简写 (b: b)
calc() { // 方法简写 (calc: function() { ... })
return this.a + this.b;
}
};
console.log("对象属性值:", myObject.a); // 输出: 1
console.log("对象方法结果:", myObject.calc()); // 输出: 3
// --- 1.5 Map 和 Reduce ---
console.log("\n--- 1.5 Map 和 Reduce ---");
const prices = [100, 200, 300];
// Map: 创建一个新数组 (打八折)
const discountedPrices = prices.map(price => price * 0.8);
console.log("八折后的价格:", discountedPrices); // 输出: [80, 160, 240]
// Reduce: 计算总价
const totalPrice = discountedPrices.reduce((acc, current) => acc + current, 0);
console.log("八折后的总价:", totalPrice); // 输出: 480
// --- 1.6 Promise (异步处理) ---
console.log("\n--- 1.6 Promise 异步处理 ---");
function fetchData(shouldSucceed) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldSucceed) {
resolve("数据加载成功!");
} else {
reject("数据加载失败!");
}
}, 500); // 模拟 0.5 秒延迟
});
}
// 成功案例
fetchData(true)
.then(message => {
console.log(`Promise 成功: ${message}`);
})
.catch(error => {
console.error(`Promise 失败: ${error}`);
});
// 失败案例
fetchData(false)
.then(message => {
console.log(`Promise 成功: ${message}`); // 不会执行
})
.catch(error => {
console.log(`Promise 失败: ${error}`); // 输出: Promise 失败: 数据加载失败!
});
// --- 1.7 模块化 (使用导入的内容) ---
// 注意:这部分取决于您是否创建了 math.js 文件
console.log("\n--- 1.7 模块化 (导入 math.js) ---");
console.log("来自 math.js 的 PI:", PI); // 输出: 3.14
console.log("来自 math.js 的 add(10, 5):", add(10, 5)); // 输出: 15
console.log("来自 math.js 的 sub(10, 5):", sub(10, 5)); // 输出: 5
</script>
</body>
</html>
math.js
javascript
// 命名导出 (Named Exports)
export const PI = 3.14;
// 命名导出
export function add(a, b) {
return a + b;
}
// 默认导出 (Default Export) - 每个模块只能有一个
const subtract = (a, b) => a - b;
export default subtract;
注意:
-
确保
es6_demo.html和math.js两个文件保存在同一个文件夹中。 -
打开 HTML: 双击
es6_demo.html文件,它会在您的浏览器中打开。 -
打开控制台: 在浏览器页面上,按
F12键(或右键点击页面 -> 选择 检查/审查元素 -> 切换到 Console/控制台 标签页)。
在这过程中,直接双击打开可能会报出错误:

这个错误是由于浏览器的安全限制导致的,报错原因:CORS 策略限制 (Cross-Origin Resource Sharing)
当你在本地文件系统 (file:/// 协议) 中直接用浏览器打开 es6_demo.html 文件时,浏览器会将其视为一个特殊且受限的"原点" (origin: 'null')。
ES6 模块的 import 语句(例如 import { PI, add } from './math.js';)本质上是一种跨域资源请求 ,即使是在同一个文件夹下,浏览器出于安全考虑,也会对 file:/// 协议下的模块加载施加严格的 CORS (跨域资源共享) 限制。
简单来说:浏览器不允许直接从本地文件系统通过 file:/// 协议加载 ES6 模块。
解决方案 ✅:
使用 VS Code 的 Live Server 插件:
如果你使用 Visual Studio Code 作为代码编辑器,这是最简单且推荐的方法:
-
安装插件: 在 VS Code 中搜索并安装 "Live Server" 插件(作者:Ritwick Dey)。
-
启动服务器: 打开您的
es6_demo.html文件,右键点击编辑器窗口,选择 "Open with Live Server"。 -
结果: 浏览器将自动打开一个地址,通常是
http://127.0.0.1:5500/es6_demo.html。在这个地址下,模块加载将正常工作,您就可以在控制台看到正确的输出了。
使用 Python 或 Node.js 启动一个简单的本地服务器:(了解即可)
如果你不使用 VS Code,可以使用命令行快速启动一个临时 Web 服务器:
选项 A: 使用 Python (如果已安装 Python)
-
打开命令行(或终端)。
-
导航到存放
es6_demo.html和math.js的文件夹。 -
运行以下命令:
bash
# 对于 Python 3
python -m http.server 8000
# 对于 Python 2 (如果仍在使用)
# python -m SimpleHTTPServer 8000
- 在浏览器中打开地址:
http://localhost:8000/es6_demo.html
选项 B: 使用 Node.js 的 http-server 模块 (如果已安装 Node.js)
1.安装 http-server:
bash
npm install -g http-server
2.导航到您的文件目录。
3.运行服务器:
bash
http-server -p 8000
4.在浏览器中打开地址:http://localhost:8000/es6_demo.html
使用上述任一方法,一旦你通过 http:// 协议访问文件,CORS 限制就会解除,模块化代码就能正常运行了。