外观
JavaScript ES6 笔记
约 2901 字大约 10 分钟
2025-08-16
1.1 什么是 ES6?
ES6 是 ECMAScript 6.0 的简称,于 2015 年 6 月正式发布,也称为 ES2015。它是 JavaScript 语言的第六版标准,旨在使 JavaScript 能够编写复杂的大型应用程序,成为企业级开发语言。
1.2 ES6 的重要性
- 解决了 ES5 的许多痛点
- 引入了更现代化的语法和功能
- 使代码更简洁、可读性更高
- 提供了更好的模块化支持
- 增强了对象和函数的处理能力
二、变量声明:let 与 const
2.1 let 声明变量
// 块级作用域
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // ReferenceError: x is not defined
// 不存在变量提升
console.log(y); // ReferenceError
let y = 20;
// 不允许重复声明
let z = 30;
let z = 40; // SyntaxError2.2 const 声明常量
// 常量必须初始化
const PI = 3.1415926;
// 不能修改基本类型值
PI = 3; // TypeError
// 对象属性可以修改
const person = { name: '张三' };
person.name = '李四'; // OK
person = { name: '王五' }; // TypeError
// 常量命名习惯:全大写加下划线
const MAX_USERS = 100;2.3 let/const vs var
| 特性 | var | let/const |
|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 |
| 变量提升 | 有 | 无(存在暂时性死区) |
| 重复声明 | 允许 | 不允许 |
| 全局对象属性 | 是(浏览器中为 window) | 否 |
最佳实践:
- 优先使用
const,只有需要重新赋值时才使用let - 避免使用
var - 在作用域顶部声明变量
三、字符串扩展
3.1 模板字符串
const name = '张三';
const age = 18;
// 基本用法
const greeting = `你好,${name}!你今年${age}岁了。`;
// 多行字符串
const html = `
<div class="user">
<h2>${name}</h2>
<p>年龄:${age}</p>
</div>
`;
// 嵌入表达式
const result = `2 + 2 = ${2 + 2}`; // "2 + 2 = 4"
// 嵌套模板
const nested = `外层 ${`内层 ${name}`}`;
// 调用函数
function format(str) {
return str.toUpperCase();
}
const message = `欢迎:${format(name)}`;3.2 常用字符串方法
// includes() - 检查是否包含字符串
'Hello'.includes('ell'); // true
// startsWith() - 检查是否以指定字符串开头
'Hello'.startsWith('He'); // true
// endsWith() - 检查是否以指定字符串结尾
'Hello'.endsWith('lo'); // true
// repeat() - 重复字符串
'ha'.repeat(3); // 'hahaha'
// trimStart() 和 trimEnd() - 去除空白
' hello '.trimStart(); // 'hello '
' hello '.trimEnd(); // ' hello'四、解构赋值
4.1 数组解构
// 基本用法
const [a, b] = [1, 2];
console.log(a, b); // 1 2
// 跳过元素
const [x, , y] = [1, 2, 3];
console.log(x, y); // 1 3
// 默认值
const [p = 10, q = 20] = [5];
console.log(p, q); // 5 20
// 剩余运算符
const [first, ...rest] = [1, 2, 3, 4];
console.log(first, rest); // 1 [2, 3, 4]
// 交换变量
let m = 1, n = 2;
[m, n] = [n, m];
console.log(m, n); // 2 1
// 函数返回多值
function returnMultipleValues() {
return [1, 2, 3];
}
const [one, two, three] = returnMultipleValues();4.2 对象解构
const person = {
name: '张三',
age: 18,
address: {
city: '北京',
street: '中关村'
}
};
// 基本用法
const { name, age } = person;
console.log(name, age); // '张三' 18
// 重命名
const { name: userName, age: userAge } = person;
console.log(userName, userAge); // '张三' 18
// 默认值
const { gender = '未知' } = person;
console.log(gender); // '未知'
// 嵌套解构
const { address: { city } } = person;
console.log(city); // '北京'
// 函数参数解构
function printPerson({ name, age }) {
console.log(`姓名:${name},年龄:${age}`);
}
printPerson(person);五、函数扩展
5.1 箭头函数
// 基本语法
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
// 单参数可省略括号
const square = x => x * x;
console.log(square(4)); // 16
// 无参数需要空括号
const getRandom = () => Math.random();
// 多行函数体需要大括号和return
const multiply = (a, b) => {
const result = a * b;
return result;
};
// 箭头函数与普通函数this的区别
const person = {
name: '张三',
age: 18,
sayHi: function() {
setTimeout(() => {
console.log(`你好,我是${this.name}`); // 能正确访问this
}, 100);
}
};
person.sayHi();箭头函数特点:
- 没有自己的
this,继承自外层作用域 - 没有
arguments对象,可用 rest 参数代替 - 不能作为构造函数
- 没有
prototype属性
5.2 默认参数
// 基本用法
function greet(name = '游客') {
console.log(`你好,${name}!`);
}
greet(); // 你好,游客!
greet('张三'); // 你好,张三!
// 默认参数可以是表达式
function logTime(time = new Date().toLocaleTimeString()) {
console.log(time);
}
// 依赖前面的参数
function multiply(a, b = a * 2) {
return a * b;
}
console.log(multiply(3)); // 185.3 Rest 参数
// 基本用法
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// 与解构结合
function logFirstTwo([first, second, ...rest]) {
console.log(first, second);
}
logFirstTwo([1, 2, 3, 4]); // 1 2
// 与普通参数结合
function format(name, ...items) {
return `${name}: ${items.join(', ')}`;
}
console.log(format('水果', '苹果', '香蕉', '橙子')); // 水果: 苹果, 香蕉, 橙子六、数组扩展
6.1 扩展运算符
// 数组合并
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4]
// 复制数组
const original = [1, 2, 3];
const copy = [...original];
// 字符串转数组
const chars = [...'hello']; // ['h', 'e', 'l', 'l', 'o']
// Math.max 使用
const numbers = [1, 2, 3, 4];
console.log(Math.max(...numbers)); // 4
// 对象合并(浅拷贝)
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3 }6.2 常用数组方法
// Array.from() - 类数组转数组
const nodeList = document.querySelectorAll('div');
const divArray = Array.from(nodeList);
// Array.of() - 创建数组
const arr = Array.of(1, 2, 3); // [1, 2, 3]
// find() - 查找第一个符合条件的元素
const numbers = [1, 3, 5, 7, 9];
const firstEven = numbers.find(n => n % 2 === 0); // undefined
const firstOdd = numbers.find(n => n % 2 === 1); // 1
// findIndex() - 查找第一个符合条件的元素索引
const index = numbers.findIndex(n => n > 5); // 3
// includes() - 检查是否包含元素
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
// fill() - 用值填充数组
new Array(3).fill(0); // [0, 0, 0]
[1, 2, 3].fill(9, 1, 2); // [1, 9, 3] (从索引1到2)七、对象扩展
7.1 简洁属性和方法
const name = '张三';
const age = 18;
// ES5
const person1 = {
name: name,
age: age,
sayHi: function() {
console.log('你好!');
}
};
// ES6 - 简洁表示法
const person2 = {
name,
age,
sayHi() {
console.log('你好!');
}
};7.2 计算属性名
// ES5
const propName = 'name';
const obj1 = {};
obj1[propName] = '张三';
// ES6
const propName = 'name';
const obj2 = {
[propName]: '张三',
['user' + 'Name']: '李四',
['say' + 'Hi']() {
console.log('你好!');
}
};7.3 Object.assign() - 对象合并
// 基本用法
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // { a: 1, b: 2, c: 3 }
// 创建对象副本(浅拷贝)
const original = { a: 1, b: { c: 2 } };
const copy = Object.assign({}, original);
// 合并默认配置
function configure(options) {
const defaults = {
theme: 'light',
fontSize: 14,
showSidebar: true
};
return Object.assign({}, defaults, options);
}7.4 Object.keys/values/entries
const person = {
name: '张三',
age: 18,
city: '北京'
};
// 获取所有键
console.log(Object.keys(person)); // ['name', 'age', 'city']
// 获取所有值
console.log(Object.values(person)); // ['张三', 18, '北京']
// 获取键值对数组
console.log(Object.entries(person));
// [['name', '张三'], ['age', 18], ['city', '北京']]
// 遍历对象
for (const [key, value] of Object.entries(person)) {
console.log(`${key}: ${value}`);
}八、Promise
8.1 Promise 基础
// 创建Promise
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.3;
if (success) {
resolve('数据获取成功');
} else {
reject('数据获取失败');
}
}, 1000);
});
};
// 使用Promise
fetchData()
.then(data => {
console.log(data); // 数据获取成功
return '处理后的数据';
})
.then(processedData => {
console.log(processedData); // 处理后的数据
})
.catch(error => {
console.error(error); // 数据获取失败
})
.finally(() => {
console.log('请求完成');
});8.2 Promise 静态方法
// Promise.resolve()
const p1 = Promise.resolve(42);
p1.then(value => console.log(value)); // 42
// Promise.reject()
const p2 = Promise.reject('出错了');
p2.catch(error => console.log(error)); // 出错了
// Promise.all() - 全部成功才成功
const p3 = Promise.resolve(3);
const p4 = new Promise((resolve) => setTimeout(resolve, 100, 'foo'));
const p5 = Promise.resolve(5);
Promise.all([p3, p4, p5])
.then(values => console.log(values)) // [3, 'foo', 5]
.catch(error => console.error(error));
// Promise.race() - 第一个完成的结果
const p6 = new Promise((resolve, reject) =>
setTimeout(resolve, 500, 'one'));
const p7 = new Promise((resolve, reject) =>
setTimeout(resolve, 100, 'two'));
Promise.race([p6, p7])
.then(value => console.log(value)) // 'two'
.catch(error => console.log(error));8.3 Promise 实用技巧
// 链式调用
fetchData()
.then(data => process1(data))
.then(result1 => process2(result1))
.then(result2 => {
console.log('最终结果:', result2);
})
.catch(error => {
console.error('处理过程中出错:', error);
});
// 并行执行多个Promise
const fetchUser = () => Promise.resolve({ id: 1, name: '张三' });
const fetchPosts = () => Promise.resolve([{ id: 1, title: '第一篇' }]);
Promise.all([fetchUser(), fetchPosts()])
.then(([user, posts]) => {
console.log('用户:', user);
console.log('文章:', posts);
});
// 错误处理
function safeFetch(url) {
return fetch(url)
.catch(error => {
console.error('请求出错:', error);
return { error: true, message: error.message };
});
}九、Class
9.1 Class 基础
// ES5 构造函数
function PersonES5(name, age) {
this.name = name;
this.age = age;
}
PersonES5.prototype.sayHi = function() {
console.log(`你好,我是${this.name}`);
};
// ES6 Class
class Person {
// 构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
sayHi() {
console.log(`你好,我是${this.name}`);
}
// 静态方法
static createAnonymous() {
return new Person('匿名用户', 0);
}
}
// 使用
const p1 = new Person('张三', 18);
p1.sayHi(); // 你好,我是张三
const anonymous = Person.createAnonymous();9.2 Class 特性
// 继承
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // 必须先调用super
this.grade = grade;
}
study() {
console.log(`${this.name}正在学习`);
}
// 重写父类方法
sayHi() {
super.sayHi(); // 调用父类方法
console.log(`我是${this.grade}年级学生`);
}
}
const s1 = new Student('李四', 15, '初三');
s1.sayHi();
s1.study();
// getter/setter
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
get fahrenheit() {
return this.celsius * 1.8 + 32;
}
set fahrenheit(value) {
this.celsius = (value - 32) / 1.8;
}
}
const temp = new Temperature(25);
console.log(temp.fahrenheit); // 77
temp.fahrenheit = 100;
console.log(temp.celsius); // 37.789.3 Class 注意事项
class本质是语法糖,底层仍是基于原型的- 类内部默认使用严格模式
- 类声明不会被提升(与
let和const类似) - 类方法之间不需要逗号分隔
constructor是构造方法,一个类只能有一个
十、模块化
10.1 导出模块
// math.js
// 导出单个变量
export const PI = 3.1415926;
// 导出多个变量
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// 导出函数
export function multiply(a, b) {
return a * b;
}
// 导出类
export class Calculator {
constructor() {
this.result = 0;
}
add(value) {
this.result += value;
return this;
}
}
// 默认导出(一个模块只能有一个)
export default function divide(a, b) {
return a / b;
}
// 重命名导出
function square(x) { return x * x; }
export { square as calculateSquare };
// 导出整个模块
export * from './utils';10.2 导入模块
// 导入单个命名导出
import { add, subtract } from './math.js';
// 导入所有命名导出
import * as math from './math.js';
console.log(math.add(2, 3)); // 5
// 导入默认导出
import divide from './math.js';
// 或者
import customName from './math.js';
// 导入命名导出和默认导出
import divide, { add, subtract } from './math.js';
// 重命名导入
import { add as sum, subtract as diff } from './math.js';
// 只导入模块不导入任何绑定(执行模块中的代码)
import './analytics.js';
// 动态导入(异步)
button.addEventListener('click', () => {
import('./lazy-loaded-module.js')
.then(module => {
module.doSomething();
})
.catch(error => {
console.error('加载失败:', error);
});
});10.3 模块化最佳实践
- 一个文件一个模块,模块名与文件名一致
- 优先使用命名导出,便于重命名导入
- 为库提供默认导出,便于用户快速使用
- 避免混合使用默认导出和命名导出
- 使用树摇(tree shaking)优化生产环境代码
十一、其他常用特性
11.1 for...of 循环
// 遍历数组
const colors = ['red', 'green', 'blue'];
for (const color of colors) {
console.log(color);
}
// 遍历字符串
for (const char of 'hello') {
console.log(char);
}
// 遍历Map
const map = new Map();
map.set('name', '张三');
map.set('age', 18);
for (const [key, value] of map) {
console.log(key, value);
}
// 遍历Set
const set = new Set([1, 2, 3]);
for (const item of set) {
console.log(item);
}
// 遍历类数组对象
const nodeList = document.querySelectorAll('div');
for (const node of nodeList) {
console.log(node);
}11.2 Set 和 Map
// Set - 无重复值的集合
const uniqueNumbers = new Set([1, 2, 3, 2, 1]);
console.log(uniqueNumbers); // Set {1, 2, 3}
// 常用方法
uniqueNumbers.add(4); // 添加
uniqueNumbers.has(3); // true
uniqueNumbers.delete(2); // 删除
uniqueNumbers.size; // 3
uniqueNumbers.clear(); // 清空
// 数组去重
const arr = [1, 2, 3, 2, 1];
const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
// Map - 键值对集合
const userMap = new Map();
userMap.set('name', '张三');
userMap.set('age', 18);
userMap.set({ id: 1 }, '对象作为键');
// 常用方法
userMap.get('name'); // '张三'
userMap.has('age'); // true
userMap.delete('age');
userMap.size; // 2
// 遍历
for (const [key, value] of userMap) {
console.log(key, value);
}11.3 模块化开发实践
// utils.js - 工具函数
export function formatDate(date) {
return date.toLocaleDateString();
}
export function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// api.js - API 请求
import { capitalize } from './utils.js';
export async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
data.name = capitalize(data.name);
return data;
}
// main.js - 主程序
import { formatDate } from './utils.js';
import { fetchUser } from './api.js';
async function init() {
try {
const user = await fetchUser(1);
console.log(`用户: ${user.name}`);
console.log(`注册日期: ${formatDate(new Date(user.registered))}`);
} catch (error) {
console.error('加载用户失败:', error);
}
}
init();