ES6+新特性:现代JavaScript的强大功能
今天我们要学习ES6+的新特性!从ES2015开始,JavaScript迎来了翻天覆地的变化,这些新特性让我们的代码更加简洁、优雅和强大。
🎯 本周学习目标
✅ 掌握箭头函数和模板字符串的使用
✅ 深入理解let/const和块级作用域
✅ 学会ES6类和继承语法
✅ 掌握模块化编程思想
✅ 了解其他重要的ES6+特性
🏹 第一部分:箭头函数
1️⃣ 箭头函数基础语法
// 传统函数表达式
const add = function(a, b) {
return a + b;
};
// 箭头函数
const addArrow = (a, b) => {
return a + b;
};
// 简化写法(单表达式)
const addSimple = (a, b) => a + b;
// 单参数可以省略括号
const double = x => x * 2;
// 无参数需要空括号
const greet = () => 'Hello World!';
// 返回对象需要用括号包裹
const createUser = (name, age) => ({
name: name,
age: age,
id: Math.random()
});
// 多行箭头函数
const processData = (data) => {
const processed = data.map(item => item.toUpperCase());
const filtered = processed.filter(item => item.length > 3);
return filtered.sort();
};
console.log(add(2, 3)); // 5
console.log(addArrow(2, 3)); // 5
console.log(addSimple(2, 3)); // 5
console.log(double(4)); // 8
console.log(greet()); // 'Hello World!'
console.log(createUser('张三', 25));
2️⃣ 箭头函数的this绑定
// 传统函数的this
const traditionalObj = {
name: '传统对象',
methods: {
regularFunction: function() {
console.log('Regular function this:', this.name);
// 嵌套函数中的this指向全局对象
function nested() {
console.log('Nested function this:', this.name); // undefined
}
nested();
},
arrowFunction: () => {
// 箭头函数没有自己的this,继承外层作用域
console.log('Arrow function this:', this.name); // undefined
}
}
};
// 箭头函数的this继承
const modernObj = {
name: '现代对象',
items: ['item1', 'item2', 'item3'],
// 使用传统函数作为方法
processItems: function() {
console.log('Processing items for:', this.name);
// 箭头函数继承外层的this
this.items.forEach(item => {
console.log(`${this.name} processing ${item}`);
});
// 如果使用传统函数,需要bind或保存this
this.items.forEach(function(item) {
console.log(`${this.name} processing ${item}`); // this.name是undefined
}.bind(this));
},
// 箭头函数作为方法(不推荐)
arrowMethod: () => {
console.log('Arrow method this:', this.name); // undefined
}
};
traditionalObj.methods.regularFunction();
modernObj.processItems();
// 事件处理中的this
class Button {
constructor(element) {
this.element = element;
this.clickCount = 0;
// 箭头函数自动绑定this
this.element.addEventListener('click', () => {
this.clickCount++;
console.log(`Button clicked ${this.clickCount} times`);
});
// 传统函数需要手动绑定
this.element.addEventListener('click', function() {
console.log('Traditional function this:', this); // 指向element
});
}
}
3️⃣ 箭头函数的限制
// 1. 不能作为构造函数
const ArrowConstructor = () => {
this.name = 'test';
};
// new ArrowConstructor(); // TypeError: ArrowConstructor is not a constructor
// 2. 没有arguments对象
function traditionalFunction() {
console.log('Arguments:', arguments);
}
const arrowFunction = () => {
// console.log(arguments); // ReferenceError: arguments is not defined
// 使用剩余参数代替
};
const arrowWithRest = (...args) => {
console.log('Rest parameters:', args);
};
traditionalFunction(1, 2, 3);
arrowWithRest(1, 2, 3);
// 3. 不能使用yield关键字
// const generatorArrow = () => {
// yield 1; // SyntaxError
// };
// 4. 没有prototype属性
function regularFunc() {}
const arrowFunc = () => {};
console.log('Regular function prototype:', regularFunc.prototype);
console.log('Arrow function prototype:', arrowFunc.prototype); // undefined
📝 第二部分:模板字符串
1️⃣ 基础语法
// 传统字符串拼接
const name = '张三';
const age = 25;
const city = '北京';
const traditionalString = '我叫' + name + ',今年' + age + '岁,住在' + city;
console.log(traditionalString);
// 模板字符串
const templateString = `我叫${name},今年${age}岁,住在${city}`;
console.log(templateString);
// 多行字符串
const multiLine = `
这是一个
多行字符串
可以保持格式
`;
console.log(multiLine);
// 表达式计算
const price = 100;
const tax = 0.1;
const total = `总价:${price * (1 + tax)}元`;
console.log(total);
// 函数调用
const formatDate = (date) => date.toLocaleDateString();
const today = new Date();
const dateString = `今天是:${formatDate(today)}`;
console.log(dateString);
2️⃣ 标签模板
// 标签函数
function highlight(strings, ...values) {
console.log('Strings:', strings);
console.log('Values:', values);
return strings.reduce((result, string, i) => {
const value = values[i] ? `<mark>${values[i]}</mark>` : '';
return result + string + value;
}, '');
}
const user = '李四';
const score = 95;
const highlighted = highlight`用户 ${user} 的分数是 ${score}`;
console.log(highlighted);
// 实用的标签函数
function sql(strings, ...values) {
// 简单的SQL注入防护
const escapedValues = values.map(value => {
if (typeof value === 'string') {
return value.replace(/'/g, "''");
}
return value;
});
return strings.reduce((result, string, i) => {
const value = escapedValues[i] !== undefined ? `'${escapedValues[i]}'` : '';
return result + string + value;
}, '');
}
const userId = 123;
const userName = "O'Connor";
const query = sql`SELECT * FROM users WHERE id = ${userId} AND name = ${userName}`;
console.log(query);
// 样式标签函数
function css(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] || '';
return result + string + value;
}, '');
}
const primaryColor = '#007bff';
const fontSize = '16px';
const styles = css`
.button {
background-color: ${primaryColor};
font-size: ${fontSize};
border: none;
padding: 10px 20px;
}
`;
console.log(styles);
🔒 第三部分:let、const和块级作用域
1️⃣ var的问题
// var的函数作用域问题
function varProblems() {
console.log('开始函数执行');
if (true) {
var x = 1;
}
console.log('x在if外部:', x); // 1,var没有块级作用域
// 变量提升问题
console.log('y在声明前:', y); // undefined,而不是报错
var y = 2;
console.log('y在声明后:', y); // 2
// 循环中的问题
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log('var循环:', i); // 输出3次3
}, 100);
}
}
varProblems();
// var的重复声明问题
var message = '第一次声明';
var message = '第二次声明'; // 不会报错
console.log(message); // '第二次声明'
2️⃣ let和const的改进
// let的块级作用域
function letImprovements() {
if (true) {
let x = 1;
const y = 2;
}
// console.log(x); // ReferenceError: x is not defined
// console.log(y); // ReferenceError: y is not defined
// 暂时性死区
// console.log(z); // ReferenceError: Cannot access 'z' before initialization
let z = 3;
console.log('z:', z);
// 循环中的let
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log('let循环:', i); // 输出0, 1, 2
}, 200);
}
// 不能重复声明
let unique = 'first';
// let unique = 'second'; // SyntaxError: Identifier 'unique' has already been declared
}
letImprovements();
// const的特性
function constFeatures() {
// 必须初始化
// const a; // SyntaxError: Missing initializer in const declaration
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable
// 对象和数组的const
const user = { name: '张三', age: 25 };
user.age = 26; // 可以修改属性
user.city = '北京'; // 可以添加属性
// user = {}; // TypeError: Assignment to constant variable
const numbers = [1, 2, 3];
numbers.push(4); // 可以修改数组内容
numbers[0] = 0; // 可以修改元素
// numbers = []; // TypeError: Assignment to constant variable
console.log('User:', user);
console.log('Numbers:', numbers);
// 冻结对象
const frozenUser = Object.freeze({ name: '李四', age: 30 });
// frozenUser.age = 31; // 严格模式下会报错,非严格模式下静默失败
console.log('Frozen user:', frozenUser);
}
constFeatures();
3️⃣ 块级作用域的应用
// 立即执行函数的替代
// 传统IIFE
(function() {
var privateVar = 'private';
console.log('IIFE:', privateVar);
})();
// 块级作用域替代
{
let privateVar = 'private';
const privateConst = 'constant';
console.log('Block scope:', privateVar, privateConst);
}
// console.log(privateVar); // ReferenceError
// switch语句中的块级作用域
function switchExample(type) {
switch (type) {
case 'A': {
let message = 'Type A';
console.log(message);
break;
}
case 'B': {
let message = 'Type B'; // 不会与上面的message冲突
console.log(message);
break;
}
default: {
let message = 'Unknown type';
console.log(message);
}
}
}
switchExample('A');
switchExample('B');
// 循环中的块级作用域
function loopExamples() {
// for循环的块级作用域
for (let i = 0; i < 3; i++) {
let squared = i * i;
console.log(`${i} squared is ${squared}`);
}
// console.log(i); // ReferenceError
// console.log(squared); // ReferenceError
// for...of循环
const fruits = ['apple', 'banana', 'orange'];
for (const fruit of fruits) {
console.log(`I like ${fruit}`);
}
// console.log(fruit); // ReferenceError
// for...in循环
const person = { name: '王五', age: 28, city: '上海' };
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// console.log(key); // ReferenceError
}
loopExamples();
🏛️ 第四部分:类和继承
1️⃣ ES6类语法
// 传统构造函数
function TraditionalPerson(name, age) {
this.name = name;
this.age = age;
}
TraditionalPerson.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
TraditionalPerson.prototype.getAge = function() {
return this.age;
};
// ES6类语法
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
this._id = Math.random(); // 私有属性约定
}
// 实例方法
greet() {
return `Hello, I'm ${this.name}`;
}
getAge() {
return this.age;
}
// getter和setter
get id() {
return this._id;
}
set age(newAge) {
if (newAge > 0 && newAge < 150) {
this._age = newAge;
} else {
throw new Error('Invalid age');
}
}
get age() {
return this._age;
}
// 静态方法
static createAdult(name) {
return new Person(name, 18);
}
static isValidAge(age) {
return age > 0 && age < 150;
}
}
// 使用类
const person1 = new Person('张三', 25);
console.log(person1.greet());
console.log('ID:', person1.id);
const adult = Person.createAdult('李四');
console.log(adult.greet());
console.log('Is valid age:', Person.isValidAge(25));
2️⃣ 继承
// 基类
class Animal {
constructor(name, species) {
this.name = name;
this.species = species;
}
makeSound() {
return `${this.name} makes a sound`;
}
move() {
return `${this.name} moves`;
}
toString() {
return `${this.name} is a ${this.species}`;
}
static getKingdom() {
return 'Animalia';
}
}
// 派生类
class Dog extends Animal {
constructor(name, breed) {
super(name, 'Dog'); // 调用父类构造函数
this.breed = breed;
}
// 重写父类方法
makeSound() {
return `${this.name} barks: Woof!`;
}
// 新增方法
fetch() {
return `${this.name} fetches the ball`;
}
// 调用父类方法
move() {
return super.move() + ' by running';
}
toString() {
return super.toString() + ` (${this.breed})`;
}
}
class Cat extends Animal {
constructor(name, color) {
super(name, 'Cat');
this.color = color;
}
makeSound() {
return `${this.name} meows: Meow!`;
}
climb() {
return `${this.name} climbs the tree`;
}
move() {
return super.move() + ' by sneaking';
}
}
// 使用继承
const dog = new Dog('旺财', 'Golden Retriever');
const cat = new Cat('咪咪', 'Orange');
console.log(dog.toString());
console.log(dog.makeSound());
console.log(dog.fetch());
console.log(dog.move());
console.log(cat.toString());
console.log(cat.makeSound());
console.log(cat.climb());
console.log(cat.move());
// 静态方法继承
console.log('Kingdom:', Dog.getKingdom());
// instanceof检查
console.log('dog instanceof Dog:', dog instanceof Dog);
console.log('dog instanceof Animal:', dog instanceof Animal);
console.log('cat instanceof Dog:', cat instanceof Dog);
3️⃣ 私有字段和方法(ES2022)
class BankAccount {
// 私有字段
#balance = 0;
#accountNumber;
// 静态私有字段
static #bankName = 'ES6+ Bank';
constructor(accountNumber, initialBalance = 0) {
this.#accountNumber = accountNumber;
this.#balance = initialBalance;
}
// 私有方法
#validateAmount(amount) {
return amount > 0 && typeof amount === 'number';
}
#log(operation, amount) {
console.log(`${operation}: ${amount}, Balance: ${this.#balance}`);
}
// 公共方法
deposit(amount) {
if (this.#validateAmount(amount)) {
this.#balance += amount;
this.#log('Deposit', amount);
return true;
}
return false;
}
withdraw(amount) {
if (this.#validateAmount(amount) && amount <= this.#balance) {
this.#balance -= amount;
this.#log('Withdraw', amount);
return true;
}
return false;
}
getBalance() {
return this.#balance;
}
getAccountInfo() {
return {
accountNumber: this.#accountNumber,
balance: this.#balance
};
}
// 静态私有方法
static #validateBankCode(code) {
return code.length === 4;
}
static createAccount(bankCode, accountNumber) {
if (this.#validateBankCode(bankCode)) {
return new BankAccount(`${bankCode}-${accountNumber}`);
}
throw new Error('Invalid bank code');
}
}
// 使用私有字段
const account = new BankAccount('12345', 1000);
console.log('Initial balance:', account.getBalance());
account.deposit(500);
account.withdraw(200);
// console.log(account.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class
const newAccount = BankAccount.createAccount('1234', '67890');
console.log('New account:', newAccount.getAccountInfo());
📦 第五部分:模块化编程
1️⃣ 导出模块
// math.js - 命名导出
export const PI = 3.14159;
export const E = 2.71828;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
export class Calculator {
constructor() {
this.result = 0;
}
add(value) {
this.result += value;
return this;
}
multiply(value) {
this.result *= value;
return this;
}
getResult() {
return this.result;
}
reset() {
this.result = 0;
return this;
}
}
// 批量导出
const subtract = (a, b) => a - b;
const divide = (a, b) => b !== 0 ? a / b : null;
export { subtract, divide };
// 重命名导出
const power = (base, exponent) => Math.pow(base, exponent);
export { power as pow };
// utils.js - 默认导出
export default class StringUtils {
static capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
static reverse(str) {
return str.split('').reverse().join('');
}
static truncate(str, length) {
return str.length > length ? str.slice(0, length) + '...' : str;
}
}
// 混合导出
export const VERSION = '1.0.0';
export function formatString(str) {
return str.trim().toLowerCase();
}
// config.js - 配置导出
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
export default config;
export const { apiUrl, timeout, retries } = config;
2️⃣ 导入模块
// main.js - 导入模块
// 命名导入
import { add, multiply, PI } from './math.js';
console.log('Add:', add(2, 3));
console.log('Multiply:', multiply(4, 5));
console.log('PI:', PI);
// 重命名导入
import { subtract as minus, divide as div } from './math.js';
console.log('Subtract:', minus(10, 3));
console.log('Divide:', div(15, 3));
// 导入所有命名导出
import * as MathUtils from './math.js';
console.log('All math utils:', Object.keys(MathUtils));
console.log('Using namespace:', MathUtils.add(1, 2));
// 默认导入
import StringUtils from './utils.js';
console.log('Capitalize:', StringUtils.capitalize('hello'));
console.log('Reverse:', StringUtils.reverse('world'));
// 混合导入
import config, { apiUrl, timeout } from './config.js';
console.log('Config:', config);
console.log('API URL:', apiUrl);
console.log('Timeout:', timeout);
// 动态导入
async function loadMathModule() {
try {
const mathModule = await import('./math.js');
console.log('Dynamic import:', mathModule.add(5, 5));
const { Calculator } = mathModule;
const calc = new Calculator();
const result = calc.add(10).multiply(2).getResult();
console.log('Calculator result:', result);
} catch (error) {
console.error('Failed to load module:', error);
}
}
loadMathModule();
// 条件导入
async function conditionalImport(useAdvanced) {
if (useAdvanced) {
const { default: AdvancedUtils } = await import('./advanced-utils.js');
return AdvancedUtils;
} else {
const { default: BasicUtils } = await import('./basic-utils.js');
return BasicUtils;
}
}
// 重新导出
// index.js - 统一导出入口
export { add, multiply, subtract, divide } from './math.js';
export { default as StringUtils } from './utils.js';
export { default as config } from './config.js';
// 重新导出并重命名
export { Calculator as MathCalculator } from './math.js';
3️⃣ 模块化最佳实践
// logger.js - 单例模式模块
class Logger {
constructor() {
this.logs = [];
this.level = 'info';
}
setLevel(level) {
this.level = level;
}
log(message, level = 'info') {
const timestamp = new Date().toISOString();
const logEntry = { timestamp, message, level };
this.logs.push(logEntry);
if (this.shouldLog(level)) {
console.log(`[${timestamp}] ${level.toUpperCase()}: ${message}`);
}
}
shouldLog(level) {
const levels = ['debug', 'info', 'warn', 'error'];
return levels.indexOf(level) >= levels.indexOf(this.level);
}
getLogs() {
return [...this.logs];
}
clear() {
this.logs = [];
}
}
// 导出单例实例
export default new Logger();
// api.js - API模块
import config from './config.js';
import logger from './logger.js';
class APIClient {
constructor(baseURL) {
this.baseURL = baseURL;
this.defaultHeaders = {
'Content-Type': 'application/json'
};
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
headers: { ...this.defaultHeaders, ...options.headers },
...options
};
logger.log(`Making request to ${url}`, 'debug');
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
logger.log(`Request successful: ${url}`, 'info');
return data;
} catch (error) {
logger.log(`Request failed: ${error.message}`, 'error');
throw error;
}
}
get(endpoint, params = {}) {
const queryString = new URLSearchParams(params).toString();
const url = queryString ? `${endpoint}?${queryString}` : endpoint;
return this.request(url);
}
post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
}
// 导出配置好的实例
export default new APIClient(config.apiUrl);
// 也导出类,允许创建新实例
export { APIClient };
// app.js - 应用入口
import api from './api.js';
import logger from './logger.js';
import { Calculator } from './math.js';
class App {
constructor() {
this.calculator = new Calculator();
this.init();
}
async init() {
logger.log('Application starting...', 'info');
try {
// 使用API
const data = await api.get('/users');
logger.log(`Loaded ${data.length} users`, 'info');
// 使用计算器
const result = this.calculator.add(10).multiply(2).getResult();
logger.log(`Calculation result: ${result}`, 'info');
logger.log('Application initialized successfully', 'info');
} catch (error) {
logger.log(`Application initialization failed: ${error.message}`, 'error');
}
}
}
// 启动应用
new App();
💡 本周总结
🎯 核心知识点
- 箭头函数:简洁语法、this绑定、使用限制
- 模板字符串:字符串插值、多行字符串、标签模板
- let/const:块级作用域、暂时性死区、常量特性
- 类和继承:class语法、继承机制、私有字段
- 模块化:导入导出、动态导入、模块组织
📝 最佳实践
✅ 优先使用const,需要重新赋值时使用let
✅ 在对象方法中谨慎使用箭头函数
✅ 使用模板字符串进行字符串拼接
✅ 用class语法替代构造函数
✅ 合理组织模块,保持单一职责
🤔 思考题
- 箭头函数什么时候不适合使用?
- 如何实现真正的私有属性?
- 模块化有什么优势?如何避免循环依赖?
📚 下周预告
下周我们将进行 JavaScript实战项目,综合运用所学知识!
内容包括:
- 项目架构设计
- 代码组织和模块化
- 调试技巧和工具使用
- 性能优化基础
🎉 写在最后
ES6+的新特性让JavaScript变得更加现代化和强大,掌握它们是成为优秀前端开发者的必经之路!
如果这篇文章对你有帮助:
👍 请点个赞,让更多人看到
🔄 转发分享,帮助更多学习ES6+的朋友
💬 评论区留言,分享你最喜欢的ES6+特性
关于作者
每周更新实用的前端教程,从入门到进阶
关注我,一起在前端的道路上成长!
#JavaScript #ES6 #箭头函数 #模板字符串 #类和继承 #模块化