ES6 (ECMAScript 2015+)

ES6 ​ 是 ECMAScript 6 的简称,也称为 ECMAScript 2015(ES2015)。它是 JavaScript 语言的重大更新,引入了许多现代语法特性和功能。

目录

[Let 变量定义](#Let 变量定义)

结构表达式

函数优化

对象优化

[Map 和 Reduce](#Map 和 Reduce)

promise

模块化

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)的增强,让对象创建更方便。主要包括:

  1. 属性名简写 (Shorthand Property Names): 如果对象属性名与变量名相同,可以直接简写。

  2. 方法简写 (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

MapReduce数组原型 上新增的两个非常常用的高阶函数(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 有三种状态:

  1. Pending (进行中): 初始状态。

  2. Fulfilled (已成功): 操作成功完成。

  3. 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 引入了原生的 模块系统 ,允许您将代码分割成可重用的文件(模块),并通过标准化的 importexport 语法来共享功能。

  • 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;

注意:

  1. 确保 es6_demo.htmlmath.js 两个文件保存在同一个文件夹中。

  2. 打开 HTML: 双击 es6_demo.html 文件,它会在您的浏览器中打开。

  3. 打开控制台: 在浏览器页面上,按 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 作为代码编辑器,这是最简单且推荐的方法:

  1. 安装插件: 在 VS Code 中搜索并安装 "Live Server" 插件(作者:Ritwick Dey)。

  2. 启动服务器: 打开您的 es6_demo.html 文件,右键点击编辑器窗口,选择 "Open with Live Server"

  3. 结果: 浏览器将自动打开一个地址,通常是 http://127.0.0.1:5500/es6_demo.html。在这个地址下,模块加载将正常工作,您就可以在控制台看到正确的输出了。


使用 Python 或 Node.js 启动一个简单的本地服务器:(了解即可)

如果你不使用 VS Code,可以使用命令行快速启动一个临时 Web 服务器:

选项 A: 使用 Python (如果已安装 Python)

  1. 打开命令行(或终端)。

  2. 导航到存放 es6_demo.htmlmath.js 的文件夹。

  3. 运行以下命令:

bash 复制代码
# 对于 Python 3
python -m http.server 8000

# 对于 Python 2 (如果仍在使用)
# python -m SimpleHTTPServer 8000
  1. 在浏览器中打开地址: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 限制就会解除,模块化代码就能正常运行了。

相关推荐
凤凰战士芭比Q2 小时前
web中间件——(二)Nginx(高级功能、优化)
前端·nginx·中间件
阿珊和她的猫2 小时前
表单数据验证:HTML5 自带属性与其他方法的结合应用
前端·状态模式·html5
谷粒.3 小时前
Cypress vs Playwright vs Selenium:现代Web自动化测试框架深度评测
java·前端·网络·人工智能·python·selenium·测试工具
小飞侠在吗9 小时前
vue props
前端·javascript·vue.js
DsirNg10 小时前
页面栈溢出问题修复总结
前端·微信小程序
小徐_233310 小时前
uni-app 也能远程调试?使用 PageSpy 打开调试的新大门!
前端·微信小程序·uni-app
大怪v10 小时前
【Virtual World 03】上帝之手
前端·javascript
别叫我->学废了->lol在线等12 小时前
演示 hasattr 和 ** 解包操作符
开发语言·前端·python
霍夫曼12 小时前
UTC时间与本地时间转换问题
java·linux·服务器·前端·javascript