JS 高级特性与ES6+语法
2025/9/17大约 10 分钟
JavaScript高级特性与ES6+语法
学习目标
- 理解作用域、作用域链和闭包概念
- 掌握let、const与var的区别
- 学会使用箭头函数和解构赋值
- 了解ES6+类语法和面向对象编程
作用域与作用域链
作用域基础
作用域决定了变量的可访问性。JavaScript有三种作用域:
点击展开示例
// 全局作用域
var globalVar = '全局变量';
let globalLet = '全局let';
const globalConst = '全局const';
function outerFunction() {
// 函数作用域
var functionVar = '函数变量';
if (true) {
// 块级作用域(ES6+)
let blockLet = '块级let';
const blockConst = '块级const';
var functionScoped = '函数作用域的var';
console.log(blockLet); // 可访问
console.log(globalVar); // 可访问
}
console.log(functionScoped); // 可访问
// console.log(blockLet); // 错误:不可访问
}
// 作用域链示例
function outer() {
let outerVar = 'outer';
function middle() {
let middleVar = 'middle';
function inner() {
let innerVar = 'inner';
// 可以访问所有外层作用域的变量
console.log(innerVar); // 'inner'
console.log(middleVar); // 'middle'
console.log(outerVar); // 'outer'
console.log(globalVar); // '全局变量'
}
inner();
}
middle();
}
outer();
变量提升
// var的提升
console.log(hoistedVar); // undefined(不是错误)
var hoistedVar = '提升的变量';
// 等价于:
// var hoistedVar;
// console.log(hoistedVar);
// hoistedVar = '提升的变量';
// 函数提升
console.log(hoistedFunction()); // "我被提升了"
function hoistedFunction() {
return "我被提升了";
}
// let和const不会提升到可用状态
// console.log(notHoisted); // 错误:Cannot access before initialization
let notHoisted = '不会提升';
let、const与var的区别
作用域差异
// var:函数作用域
function varExample() {
if (true) {
var x = 1;
}
console.log(x); // 1(可访问)
}
// let/const:块级作用域
function letExample() {
if (true) {
let y = 1;
const z = 1;
}
// console.log(y); // 错误:y未定义
// console.log(z); // 错误:z未定义
}
// 循环中的差异
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log('var:', i), 100); // 输出:3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log('let:', j), 100); // 输出:0, 1, 2
}
重复声明和重新赋值
// var允许重复声明
var name = '张三';
var name = '李四'; // 不报错
console.log(name); // '李四'
// let不允许重复声明
let age = 25;
// let age = 30; // 错误:Identifier 'age' has already been declared
age = 30; // 可以重新赋值
// const不允许重复声明和重新赋值
const PI = 3.14159;
// const PI = 3.14; // 错误:重复声明
// PI = 3.14; // 错误:不能重新赋值
// 但const对象的属性可以修改
const person = { name: '张三', age: 25 };
person.age = 26; // 可以
person.city = '北京'; // 可以
console.log(person); // { name: '张三', age: 26, city: '北京' }
最佳实践
// 推荐的声明顺序:const > let > var
// 1. 优先使用const(不会改变的值)
const API_URL = 'https://api.example.com';
const MAX_RETRY = 3;
const users = []; // 数组引用不变,但内容可以改变
// 2. 需要重新赋值时使用let
let currentUser = null;
let isLoading = false;
for (let i = 0; i < users.length; i++) {
// 循环变量使用let
}
// 3. 避免使用var(除非需要兼容老版本浏览器)
闭包
闭包基础
闭包是指函数能够访问其外部作用域的变量,即使外部函数已经执行完毕。
// 基本闭包示例
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter2()); // 1(独立的计数器)
console.log(counter1()); // 3
闭包的实际应用
点击展开示例
// 1. 模块模式
const Calculator = (function() {
let result = 0;
return {
add: function(x) {
result += x;
return this;
},
subtract: function(x) {
result -= x;
return this;
},
multiply: function(x) {
result *= x;
return this;
},
getResult: function() {
return result;
},
reset: function() {
result = 0;
return this;
}
};
})();
// 链式调用
const finalResult = Calculator
.add(10)
.multiply(2)
.subtract(5)
.getResult();
console.log(finalResult); // 15
// 2. 函数工厂
function createMultiplier(multiplier) {
return function(x) {
return x * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// 3. 私有变量
function createPerson(name) {
let _name = name;
let _age = 0;
return {
getName: () => _name,
getAge: () => _age,
setAge: (age) => {
if (age >= 0 && age <= 150) {
_age = age;
}
},
introduce: () => `我是${_name},今年${_age}岁`
};
}
const person = createPerson('张三');
person.setAge(25);
console.log(person.introduce()); // "我是张三,今年25岁"
箭头函数
基本语法
// 传统函数
function add(a, b) {
return a + b;
}
// 箭头函数
const add = (a, b) => a + b;
// 不同参数情况
const noParams = () => 'Hello World';
const oneParam = x => x * 2; // 单参数可省略括号
const multiParams = (x, y) => x + y;
// 函数体情况
const simple = x => x * 2; // 单表达式,自动返回
const complex = x => { // 多语句,需要显式返回
const result = x * 2;
console.log(result);
return result;
};
// 返回对象字面量
const createUser = (name, age) => ({ name, age });
// 或者
const createUser2 = (name, age) => {
return { name, age };
};
this绑定差异
点击展开示例
// 传统函数的this
const obj1 = {
name: '传统对象',
greet: function() {
console.log('Hello, ' + this.name);
},
delayedGreet: function() {
setTimeout(function() {
console.log('Delayed: ' + this.name); // this指向window/undefined
}, 1000);
}
};
// 箭头函数的this
const obj2 = {
name: '箭头对象',
greet: () => {
console.log('Hello, ' + this.name); // this指向外层作用域
},
delayedGreet: function() {
setTimeout(() => {
console.log('Delayed: ' + this.name); // this指向obj2
}, 1000);
}
};
// 实际应用示例
class EventHandler {
constructor() {
this.count = 0;
this.element = document.querySelector('#button');
}
// 使用箭头函数保持this指向
handleClick = () => {
this.count++;
console.log(`点击次数: ${this.count}`);
}
init() {
this.element.addEventListener('click', this.handleClick);
}
}
箭头函数的限制
// 1. 不能用作构造函数
const Person = (name) => {
this.name = name;
};
// const p = new Person('张三'); // 错误:Person is not a constructor
// 2. 没有arguments对象
function traditionalFunc() {
console.log(arguments); // 可以访问arguments
}
const arrowFunc = () => {
// console.log(arguments); // 错误:arguments未定义
console.log(...arguments); // 可以使用剩余参数
};
// 正确的方式:使用剩余参数
const arrowWithRest = (...args) => {
console.log(args);
};
// 3. 不能使用yield
// const generatorArrow = () => {
// yield 1; // 错误:箭头函数不能是生成器
// };
解构赋值
数组解构
点击展开示例
// 基本数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, third] = numbers;
console.log(first, second, third); // 1 2 3
// 跳过元素
const [a, , c] = numbers;
console.log(a, c); // 1 3
// 剩余元素
const [head, ...tail] = numbers;
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// 默认值
const [x = 0, y = 0, z = 0] = [1, 2];
console.log(x, y, z); // 1 2 0
// 交换变量
let m = 1, n = 2;
[m, n] = [n, m];
console.log(m, n); // 2 1
// 函数返回多个值
function getCoordinates() {
return [10, 20];
}
const [x, y] = getCoordinates();
console.log(x, y); // 10 20
对象解构
点击展开示例
// 基本对象解构
const user = {
name: '张三',
age: 25,
email: 'zhangsan@example.com',
address: {
city: '北京',
district: '朝阳区'
}
};
const { name, age, email } = user;
console.log(name, age, email); // 张三 25 zhangsan@example.com
// 重命名变量
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // 张三 25
// 默认值
const { name, phone = '未提供' } = user;
console.log(name, phone); // 张三 未提供
// 嵌套解构
const { address: { city, district } } = user;
console.log(city, district); // 北京 朝阳区
// 剩余属性
const { name, ...otherInfo } = user;
console.log(name); // 张三
console.log(otherInfo); // { age: 25, email: '...', address: {...} }
// 函数参数解构
function greetUser({ name, age = 0 }) {
console.log(`Hello ${name}, you are ${age} years old`);
}
greetUser(user); // Hello 张三, you are 25 years old
// 数组中的对象解构
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
];
const [{ name: firstName }, { name: secondName }] = users;
console.log(firstName, secondName); // 张三 李四
解构的实际应用
// 1. 模块导入
// import { useState, useEffect } from 'react';
// 2. API响应处理
function handleApiResponse(response) {
const {
data: { users, total },
status,
message = '操作成功'
} = response;
console.log(`状态: ${status}, 消息: ${message}`);
console.log(`用户数: ${users.length}, 总数: ${total}`);
}
// 3. 配置对象
function createServer({
port = 3000,
host = 'localhost',
ssl = false,
...options
}) {
console.log(`服务器配置: ${host}:${port}, SSL: ${ssl}`);
console.log('其他选项:', options);
}
createServer({
port: 8080,
ssl: true,
cors: true,
compression: true
});
面向对象编程
ES6类语法
点击展开示例
// 基本类定义
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
introduce() {
return `我是${this.name},今年${this.age}岁`;
}
// 静态方法
static createAdult(name) {
return new Person(name, 18);
}
// getter
get info() {
return `${this.name} (${this.age}岁)`;
}
// setter
set age(value) {
if (value >= 0 && value <= 150) {
this._age = value;
}
}
get age() {
return this._age;
}
}
// 使用类
const person = new Person('张三', 25);
console.log(person.introduce()); // 我是张三,今年25岁
console.log(person.info); // 张三 (25岁)
const adult = Person.createAdult('李四');
console.log(adult.introduce()); // 我是李四,今年18岁
继承
点击展开示例
// 继承示例
class Student extends Person {
constructor(name, age, school) {
super(name, age); // 调用父类构造函数
this.school = school;
this.grades = [];
}
// 重写父类方法
introduce() {
return `${super.introduce()},我在${this.school}上学`;
}
// 新增方法
addGrade(subject, score) {
this.grades.push({ subject, score });
}
getAverageGrade() {
if (this.grades.length === 0) return 0;
const total = this.grades.reduce((sum, grade) => sum + grade.score, 0);
return total / this.grades.length;
}
// 静态方法也可以继承
static createElementaryStudent(name) {
return new Student(name, 8, '小学');
}
}
// 使用继承
const student = new Student('王五', 16, '北京中学');
console.log(student.introduce()); // 我是王五,今年16岁,我在北京中学上学
student.addGrade('数学', 95);
student.addGrade('语文', 88);
console.log('平均分:', student.getAverageGrade()); // 91.5
私有字段(ES2022)
点击展开示例
class BankAccount {
// 私有字段
#balance = 0;
#accountNumber;
constructor(accountNumber, initialBalance = 0) {
this.#accountNumber = accountNumber;
this.#balance = initialBalance;
}
// 公共方法
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return this.#balance;
}
throw new Error('存款金额必须大于0');
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
return this.#balance;
}
throw new Error('取款金额无效');
}
// 私有方法
#validateTransaction(amount) {
return amount > 0 && amount <= this.#balance;
}
// getter访问私有字段
get balance() {
return this.#balance;
}
get accountInfo() {
return `账户: ${this.#accountNumber}, 余额: ${this.#balance}`;
}
}
const account = new BankAccount('123456789', 1000);
console.log(account.balance); // 1000
account.deposit(500);
console.log(account.accountInfo); // 账户: 123456789, 余额: 1500
// console.log(account.#balance); // 错误:私有字段不可访问
综合实例:任务管理系统
点击展开示例
class TaskManager {
#tasks = new Map();
#nextId = 1;
#categories = new Set(['工作', '学习', '生活']);
constructor() {
this.loadFromStorage();
}
// 添加任务
addTask({ title, description = '', category = '生活', priority = 'medium' }) {
const task = {
id: this.#nextId++,
title,
description,
category,
priority,
completed: false,
createdAt: new Date(),
updatedAt: new Date()
};
this.#tasks.set(task.id, task);
this.saveToStorage();
return task;
}
// 更新任务
updateTask(id, updates) {
const task = this.#tasks.get(id);
if (!task) throw new Error('任务不存在');
Object.assign(task, updates, { updatedAt: new Date() });
this.saveToStorage();
return task;
}
// 删除任务
deleteTask(id) {
const deleted = this.#tasks.delete(id);
if (deleted) this.saveToStorage();
return deleted;
}
// 获取任务列表
getTasks({ category, completed, priority } = {}) {
let tasks = Array.from(this.#tasks.values());
if (category) tasks = tasks.filter(task => task.category === category);
if (completed !== undefined) tasks = tasks.filter(task => task.completed === completed);
if (priority) tasks = tasks.filter(task => task.priority === priority);
return tasks.sort((a, b) => b.createdAt - a.createdAt);
}
// 获取统计信息
getStats() {
const tasks = Array.from(this.#tasks.values());
const total = tasks.length;
const completed = tasks.filter(task => task.completed).length;
const byCategory = {};
const byPriority = {};
tasks.forEach(task => {
byCategory[task.category] = (byCategory[task.category] || 0) + 1;
byPriority[task.priority] = (byPriority[task.priority] || 0) + 1;
});
return {
total,
completed,
pending: total - completed,
completionRate: total > 0 ? (completed / total * 100).toFixed(1) : 0,
byCategory,
byPriority
};
}
// 本地存储
saveToStorage() {
const data = {
tasks: Array.from(this.#tasks.entries()),
nextId: this.#nextId
};
localStorage.setItem('taskManager', JSON.stringify(data));
}
loadFromStorage() {
const data = localStorage.getItem('taskManager');
if (data) {
const { tasks, nextId } = JSON.parse(data);
this.#tasks = new Map(tasks);
this.#nextId = nextId;
}
}
// 导出数据
exportData() {
return {
tasks: this.getTasks(),
stats: this.getStats(),
exportDate: new Date().toISOString()
};
}
}
// 使用示例
const taskManager = new TaskManager();
// 添加任务
const task1 = taskManager.addTask({
title: '学习JavaScript',
description: '完成ES6+语法学习',
category: '学习',
priority: 'high'
});
const task2 = taskManager.addTask({
title: '写项目文档',
category: '工作',
priority: 'medium'
});
// 更新任务
taskManager.updateTask(task1.id, { completed: true });
// 获取任务列表
console.log('所有任务:', taskManager.getTasks());
console.log('学习任务:', taskManager.getTasks({ category: '学习' }));
console.log('未完成任务:', taskManager.getTasks({ completed: false }));
// 获取统计信息
console.log('统计信息:', taskManager.getStats());
最佳实践
现代JavaScript编码规范
点击展开示例
// 1. 优先使用const和let
const API_CONFIG = { baseURL: 'https://api.example.com' };
let currentUser = null;
// 2. 使用箭头函数简化代码
const users = data.map(item => ({ id: item.id, name: item.name }));
const activeUsers = users.filter(user => user.active);
// 3. 使用解构赋值
const { name, email, ...otherProps } = user;
const [first, ...rest] = items;
// 4. 使用模板字符串
const message = `Hello ${name}, you have ${count} new messages`;
// 5. 使用默认参数
function createUser(name, age = 0, active = true) {
return { name, age, active };
}
// 6. 使用剩余参数代替arguments
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// 7. 使用类而不是构造函数
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
本章小结
通过本章学习,你应该掌握了:
- ✅ 作用域、作用域链和变量提升机制
- ✅ let、const与var的区别和使用场景
- ✅ 闭包的概念和实际应用
- ✅ 箭头函数的语法和this绑定特性
- ✅ 数组和对象的解构赋值
- ✅ ES6+类语法和面向对象编程
- ✅ 私有字段和现代JavaScript特性
- ✅ 现代JavaScript的最佳实践
这些高级特性是现代JavaScript开发的基础,掌握它们将大大提升你的编程效率和代码质量。
下一步
接下来我们将学习JavaScript的异步编程,包括Promise、async/await等重要概念。