ES6+现代JavaScript特性全解析
ES6(ECMAScript 2015)及后续版本为JavaScript带来了革命性的改进,引入了类、模块、箭头函数、Promise等现代编程特性。这些特性不仅提升了开发效率,还使JavaScript成为了更强大、更优雅的编程语言。
核心价值
ES6+ = 现代语法 + 模块化 + 异步编程 + 函数式编程
- 🎯 现代语法:箭头函数、模板字符串、解构赋值等简洁语法
- 📦 模块化系统:import/export模块系统,告别全局污染
- ⚡ 异步编程:Promise、async/await,优雅处理异步操作
- 🔧 函数式编程:高阶函数、纯函数、不可变数据
- 🏗️ 面向对象增强:class语法、继承、私有字段
- 🌟 新数据结构:Map、Set、WeakMap、WeakSet等
1. 变量声明与作用域
1.1 let、const vs var
ES6引入的let和const解决了var的诸多问题,提供了更安全的变量声明方式。
变量声明对比表
| 特性 | var | let | const | 推荐使用 |
|---|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 | let/const |
| 变量提升 | 是 | 否(暂时性死区) | 否(暂时性死区) | let/const |
| 重复声明 | 允许 | 不允许 | 不允许 | let/const |
| 重新赋值 | 允许 | 允许 | 不允许 | 根据需求 |
| 全局对象属性 | 是 | 否 | 否 | let/const |
- 作用域示例
- 最佳实践
作用域与变量提升详解
作用域与变量提升完整示例
javascript
1// 1. var的函数作用域问题2function varScopeExample() {3 console.log(x); // undefined (变量提升,但未赋值)4 5 if (true) {6 var x = 1;7 console.log(x); // 18 }9 10 console.log(x); // 1 (var没有块级作用域)11}1213// 2. let的块级作用域14function letScopeExample() {15 // console.log(y); // ReferenceError: Cannot access 'y' before initialization16 17 if (true) {18 let y = 1;19 console.log(y); // 120 }21 22 // console.log(y); // ReferenceError: y is not defined23}2425// 3. const的特性26function constExample() {27 const PI = 3.14159;28 // PI = 3.14; // TypeError: Assignment to constant variable29 30 // 对象和数组的const31 const user = { name: 'John', age: 30 };32 user.age = 31; // 可以修改对象属性33 user.city = 'New York'; // 可以添加属性34 // user = {}; // TypeError: Assignment to constant variable35 36 const numbers = [1, 2, 3];37 numbers.push(4); // 可以修改数组内容38 // numbers = []; // TypeError: Assignment to constant variable39}4041// 4. 循环中的作用域问题42// var的问题43for (var i = 0; i < 3; i++) {44 setTimeout(() => {45 console.log('var:', i); // 输出: 3, 3, 346 }, 100);47}4849// let的解决方案50for (let i = 0; i < 3; i++) {51 setTimeout(() => {52 console.log('let:', i); // 输出: 0, 1, 253 }, 100);54}5556// 5. 暂时性死区(Temporal Dead Zone)57function temporalDeadZoneExample() {58 console.log(typeof x); // "undefined" (var)59 // console.log(typeof y); // ReferenceError (let)60 61 var x = 1;62 let y = 2;63}6465// 6. 全局对象属性66var globalVar = 'I am global';67let globalLet = 'I am also global';68const globalConst = 'I am global too';6970console.log(window.globalVar); // "I am global"71console.log(window.globalLet); // undefined72console.log(window.globalConst); // undefined变量声明最佳实践
变量声明最佳实践
javascript
1// 1. 优先使用const,需要重新赋值时使用let2const API_URL = 'https://api.example.com';3const users = [];4let currentUser = null;56// 2. 避免使用var7// 不推荐8var count = 0;910// 推荐11let count = 0;1213// 3. 在最小作用域内声明变量14function processUsers(userList) {15 const processedUsers = [];16 17 for (let i = 0; i < userList.length; i++) {18 const user = userList[i];19 20 if (user.active) {21 const processedUser = {22 id: user.id,23 name: user.name.toUpperCase(),24 email: user.email.toLowerCase()25 };26 processedUsers.push(processedUser);27 }28 }29 30 return processedUsers;31}3233// 4. 使用有意义的变量名34// 不推荐35const d = new Date();36const u = users.filter(x => x.a);3738// 推荐39const currentDate = new Date();40const activeUsers = users.filter(user => user.active);4142// 5. 常量使用大写字母和下划线43const MAX_RETRY_COUNT = 3;44const API_ENDPOINTS = {45 USERS: '/api/users',46 POSTS: '/api/posts'47};4849// 6. 对象和数组的不可变操作50const originalArray = [1, 2, 3];5152// 不推荐:直接修改原数组53originalArray.push(4);5455// 推荐:创建新数组56const newArray = [...originalArray, 4];5758const originalObject = { name: 'John', age: 30 };5960// 不推荐:直接修改原对象61originalObject.city = 'New York';6263// 推荐:创建新对象64const newObject = { ...originalObject, city: 'New York' };2. 箭头函数与函数增强
2.1 箭头函数语法
箭头函数是ES6引入的简洁函数语法,不仅语法更简洁,还解决了传统函数中this绑定的问题。
- 箭头函数语法
- this绑定
- 函数增强特性
箭头函数完整语法
箭头函数语法详解
javascript
1// 1. 基础语法对比2// 传统函数3function add(a, b) {4 return a + b;5}67// 箭头函数8const add = (a, b) => a + b;910// 2. 不同参数情况11// 无参数12const greet = () => 'Hello World';1314// 单个参数(可省略括号)15const double = x => x * 2;16const square = (x) => x * x; // 也可以保留括号1718// 多个参数19const multiply = (a, b) => a * b;2021// 默认参数22const greetUser = (name = 'Guest') => `Hello, ${name}!`;2324// 剩余参数25const sum = (...numbers) => numbers.reduce((acc, num) => acc + num, 0);2627// 解构参数28const getFullName = ({ firstName, lastName }) => `${firstName} ${lastName}`;2930// 3. 函数体语法31// 表达式体(隐式返回)32const isEven = n => n % 2 === 0;3334// 语句体(需要显式return)35const processData = (data) => {36 const processed = data.map(item => item.toUpperCase());37 const filtered = processed.filter(item => item.length > 3);38 return filtered;39};4041// 返回对象字面量(需要括号)42const createUser = (name, age) => ({ name, age, id: Date.now() });4344// 4. 高阶函数中的箭头函数45const numbers = [1, 2, 3, 4, 5];4647// 传统写法48const doubled = numbers.map(function(n) {49 return n * 2;50});5152// 箭头函数写法53const doubled = numbers.map(n => n * 2);5455// 链式调用56const result = numbers57 .filter(n => n > 2)58 .map(n => n * 2)59 .reduce((acc, n) => acc + n, 0);6061// 5. 复杂的函数式编程示例62const users = [63 { name: 'Alice', age: 25, active: true },64 { name: 'Bob', age: 30, active: false },65 { name: 'Charlie', age: 35, active: true }66];6768// 函数组合69const pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value);7071const processUsers = pipe(72 users => users.filter(user => user.active),73 users => users.map(user => ({ ...user, ageGroup: user.age < 30 ? 'young' : 'adult' })),74 users => users.sort((a, b) => a.age - b.age)75);7677const processedUsers = processUsers(users);7879// 6. 柯里化函数80const curry = (fn) => {81 return function curried(...args) {82 if (args.length >= fn.length) {83 return fn.apply(this, args);84 } else {85 return (...nextArgs) => curried(...args, ...nextArgs);86 }87 };88};8990// 使用箭头函数的柯里化91const add = (a, b, c) => a + b + c;92const curriedAdd = curry(add);9394const add5 = curriedAdd(5);95const add5And3 = add5(3);96const result = add5And3(2); // 109798// 7. 异步箭头函数99const fetchUserData = async (userId) => {100 try {101 const response = await fetch(`/api/users/${userId}`);102 const userData = await response.json();103 return userData;104 } catch (error) {105 console.error('Failed to fetch user:', error);106 throw error;107 }108};109110// Promise链中的箭头函数111fetchUserData(123)112 .then(user => ({ ...user, processed: true }))113 .then(user => console.log('Processed user:', user))114 .catch(error => console.error('Error:', error));this绑定机制对比
this绑定详解
javascript
1// 1. 传统函数 vs 箭头函数的this2const obj = {3 name: 'MyObject',4 5 // 传统函数方法6 traditionalMethod: function() {7 console.log('Traditional:', this.name); // 'MyObject'8 9 setTimeout(function() {10 console.log('Traditional setTimeout:', this.name); // undefined (全局this)11 }, 100);12 },13 14 // 箭头函数方法15 arrowMethod: () => {16 console.log('Arrow method:', this.name); // undefined (词法this,指向全局)17 },18 19 // 混合使用20 mixedMethod: function() {21 console.log('Mixed outer:', this.name); // 'MyObject'22 23 setTimeout(() => {24 console.log('Mixed arrow setTimeout:', this.name); // 'MyObject' (继承外层this)25 }, 100);26 }27};2829// 2. 类中的箭头函数30class EventHandler {31 constructor(name) {32 this.name = name;33 this.clickCount = 0;34 }35 36 // 传统方法37 handleClickTraditional() {38 this.clickCount++;39 console.log(`${this.name} clicked ${this.clickCount} times`);40 }41 42 // 箭头函数方法(类字段语法)43 handleClickArrow = () => {44 this.clickCount++;45 console.log(`${this.name} clicked ${this.clickCount} times`);46 }47 48 setupEventListeners() {49 const button1 = document.getElementById('btn1');50 const button2 = document.getElementById('btn2');51 52 // 传统方法需要绑定this53 button1.addEventListener('click', this.handleClickTraditional.bind(this));54 55 // 箭头函数自动绑定this56 button2.addEventListener('click', this.handleClickArrow);57 }58}5960// 3. React组件中的应用61class ReactComponent extends React.Component {62 constructor(props) {63 super(props);64 this.state = { count: 0 };65 }66 67 // 传统方法需要在constructor中绑定68 handleClickTraditional() {69 this.setState({ count: this.state.count + 1 });70 }71 72 // 箭头函数自动绑定73 handleClickArrow = () => {74 this.setState({ count: this.state.count + 1 });75 }76 77 render() {78 return (79 <div>80 <button onClick={this.handleClickTraditional.bind(this)}>81 Traditional: {this.state.count}82 </button>83 <button onClick={this.handleClickArrow}>84 Arrow: {this.state.count}85 </button>86 </div>87 );88 }89}9091// 4. 函数式编程中的this92const calculator = {93 value: 0,94 95 add: function(n) {96 this.value += n;97 return this;98 },99 100 multiply: function(n) {101 this.value *= n;102 return this;103 },104 105 // 箭头函数不适合链式调用106 // subtract: (n) => {107 // this.value -= n; // this不指向calculator108 // return this;109 // },110 111 subtract: function(n) {112 this.value -= n;113 return this;114 },115 116 getValue: function() {117 return this.value;118 }119};120121// 链式调用122const result = calculator123 .add(10)124 .multiply(2)125 .subtract(5)126 .getValue(); // 15127128// 5. 箭头函数的限制129// 不能作为构造函数130const ArrowConstructor = () => {};131// new ArrowConstructor(); // TypeError: ArrowConstructor is not a constructor132133// 没有arguments对象134function traditionalFunction() {135 console.log(arguments); // Arguments对象136}137138const arrowFunction = () => {139 // console.log(arguments); // ReferenceError: arguments is not defined140 // 使用剩余参数代替141 console.log(...args);142};143144// 不能使用call、apply、bind改变this145const arrowFunc = () => console.log(this);146const obj2 = { name: 'test' };147148arrowFunc.call(obj2); // this仍然是词法this,不是obj2ES6+函数增强特性
函数增强特性详解
javascript
1// 1. 默认参数2function greet(name = 'World', greeting = 'Hello') {3 return `${greeting}, ${name}!`;4}56// 默认参数可以是表达式7function createId(prefix = 'id', suffix = Date.now()) {8 return `${prefix}_${suffix}`;9}1011// 默认参数可以引用前面的参数12function createUser(name, role = 'user', permissions = getDefaultPermissions(role)) {13 return { name, role, permissions };14}1516function getDefaultPermissions(role) {17 const permissionMap = {18 admin: ['read', 'write', 'delete'],19 user: ['read'],20 guest: []21 };22 return permissionMap[role] || [];23}2425// 2. 剩余参数26function sum(...numbers) {27 return numbers.reduce((total, num) => total + num, 0);28}2930// 剩余参数与普通参数结合31function logMessage(level, ...messages) {32 const timestamp = new Date().toISOString();33 console.log(`[${timestamp}] ${level.toUpperCase()}:`, ...messages);34}3536logMessage('info', 'User logged in', { userId: 123 });3738// 3. 扩展运算符39const arr1 = [1, 2, 3];40const arr2 = [4, 5, 6];4142// 数组合并43const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]4445// 数组复制46const copied = [...arr1]; // [1, 2, 3]4748// 函数调用49function multiply(a, b, c) {50 return a * b * c;51}5253const numbers = [2, 3, 4];54const result = multiply(...numbers); // 245556// 4. 函数名属性57function namedFunction() {}58const anonymousFunction = function() {};59const arrowFunction = () => {};6061console.log(namedFunction.name); // 'namedFunction'62console.log(anonymousFunction.name); // 'anonymousFunction'63console.log(arrowFunction.name); // 'arrowFunction'6465// 5. 尾调用优化(理论上支持,实际支持有限)66function factorial(n, acc = 1) {67 if (n <= 1) return acc;68 return factorial(n - 1, n * acc); // 尾调用69}7071// 6. 函数参数解构72function processUser({ name, age, email = 'unknown' }) {73 console.log(`Processing ${name}, age ${age}, email ${email}`);74}7576processUser({ name: 'John', age: 30 });7778// 数组参数解构79function getCoordinates([x, y, z = 0]) {80 return { x, y, z };81}8283getCoordinates([10, 20]); // { x: 10, y: 20, z: 0 }8485// 7. 高级函数模式86// 函数组合87const compose = (...fns) => (value) => fns.reduceRight((acc, fn) => fn(acc), value);8889const addOne = x => x + 1;90const double = x => x * 2;91const square = x => x * x;9293const composedFunction = compose(square, double, addOne);94console.log(composedFunction(3)); // ((3 + 1) * 2)² = 649596// 管道操作97const pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value);9899const pipedFunction = pipe(addOne, double, square);100console.log(pipedFunction(3)); // ((3 + 1) * 2)² = 64101102// 偏函数应用103const partial = (fn, ...presetArgs) => {104 return (...laterArgs) => fn(...presetArgs, ...laterArgs);105};106107const multiply = (a, b, c) => a * b * c;108const multiplyBy2 = partial(multiply, 2);109const multiplyBy2And3 = partial(multiply, 2, 3);110111console.log(multiplyBy2(3, 4)); // 24112console.log(multiplyBy2And3(4)); // 24113114// 8. 记忆化函数115const memoize = (fn) => {116 const cache = new Map();117 118 return (...args) => {119 const key = JSON.stringify(args);120 121 if (cache.has(key)) {122 return cache.get(key);123 }124 125 const result = fn(...args);126 cache.set(key, result);127 return result;128 };129};130131const expensiveFunction = (n) => {132 console.log(`Computing for ${n}`);133 return n * n;134};135136const memoizedFunction = memoize(expensiveFunction);137138console.log(memoizedFunction(5)); // Computing for 5, returns 25139console.log(memoizedFunction(5)); // returns 25 (from cache)140141// 9. 函数重载模拟142function createOverloadedFunction(...implementations) {143 return function(...args) {144 const implementation = implementations.find(impl => 145 impl.length === args.length146 );147 148 if (implementation) {149 return implementation.apply(this, args);150 }151 152 throw new Error(`No implementation found for ${args.length} arguments`);153 };154}155156const overloadedAdd = createOverloadedFunction(157 (a) => a,158 (a, b) => a + b,159 (a, b, c) => a + b + c160);161162console.log(overloadedAdd(5)); // 5163console.log(overloadedAdd(2, 3)); // 5164console.log(overloadedAdd(1, 2, 3)); // 63. 解构赋值与扩展运算符
3.1 解构赋值语法
解构赋值允许从数组或对象中提取值,并赋给变量,是ES6中最实用的特性之一。
- 数组解构
- 对象解构
- 扩展运算符
数组解构详解
数组解构完整示例
javascript
1// 1. 基础数组解构2const colors = ['red', 'green', 'blue'];3const [first, second, third] = colors;4console.log(first, second, third); // 'red', 'green', 'blue'56// 2. 跳过元素7const [primary, , tertiary] = colors;8console.log(primary, tertiary); // 'red', 'blue'910// 3. 默认值11const [a, b, c, d = 'yellow'] = colors;12console.log(d); // 'yellow'1314// 4. 剩余元素15const numbers = [1, 2, 3, 4, 5];16const [head, ...tail] = numbers;17console.log(head); // 118console.log(tail); // [2, 3, 4, 5]1920// 5. 嵌套数组解构21const nested = [[1, 2], [3, 4], [5, 6]];22const [[x1, y1], [x2, y2]] = nested;23console.log(x1, y1, x2, y2); // 1, 2, 3, 42425// 6. 交换变量26let x = 1, y = 2;27[x, y] = [y, x];28console.log(x, y); // 2, 12930// 7. 函数返回多个值31function getCoordinates() {32 return [10, 20, 30];33}3435const [x, y, z] = getCoordinates();3637// 8. 字符串解构38const str = 'hello';39const [h, e, l1, l2, o] = str;40console.log(h, e, l1, l2, o); // 'h', 'e', 'l', 'l', 'o'4142// 9. 实际应用示例43// 处理API响应44async function fetchUserData() {45 const response = await fetch('/api/user');46 const [user, posts, comments] = await Promise.all([47 response.json(),48 fetch('/api/posts').then(r => r.json()),49 fetch('/api/comments').then(r => r.json())50 ]);51 52 return { user, posts, comments };53}5455// 数组方法链式调用56const processNumbers = (nums) => {57 const [evens, odds] = nums.reduce(58 ([evens, odds], num) => 59 num % 2 === 0 60 ? [[...evens, num], odds]61 : [evens, [...odds, num]],62 [[], []]63 );64 65 return { evens, odds };66};6768console.log(processNumbers([1, 2, 3, 4, 5])); 69// { evens: [2, 4], odds: [1, 3, 5] }7071// 10. 高级模式72// 递归解构73function flattenArray([head, ...tail]) {74 if (tail.length === 0) return [head];75 76 return Array.isArray(head) 77 ? [...flattenArray(head), ...flattenArray(tail)]78 : [head, ...flattenArray(tail)];79}8081const nestedArray = [1, [2, 3], [4, [5, 6]]];82console.log(flattenArray(nestedArray)); // [1, 2, 3, 4, 5, 6]8384// 模式匹配模拟85function processCommand([command, ...args]) {86 switch (command) {87 case 'create':88 const [type, name] = args;89 return `Creating ${type}: ${name}`;90 91 case 'delete':92 const [id] = args;93 return `Deleting item with id: ${id}`;94 95 case 'update':96 const [targetId, ...updates] = args;97 return `Updating ${targetId} with: ${updates.join(', ')}`;98 99 default:100 return 'Unknown command';101 }102}103104console.log(processCommand(['create', 'user', 'john'])); 105// "Creating user: john"对象解构详解
对象解构完整示例
javascript
1// 1. 基础对象解构2const user = {3 name: 'John Doe',4 age: 30,5 email: 'john@example.com'6};78const { name, age, email } = user;9console.log(name, age, email); // 'John Doe', 30, 'john@example.com'1011// 2. 重命名变量12const { name: userName, age: userAge } = user;13console.log(userName, userAge); // 'John Doe', 301415// 3. 默认值16const { name, age, city = 'Unknown' } = user;17console.log(city); // 'Unknown'1819// 4. 重命名 + 默认值20const { email: userEmail = 'no-email' } = user;2122// 5. 嵌套对象解构23const userProfile = {24 personal: {25 name: 'Alice',26 age: 2527 },28 contact: {29 email: 'alice@example.com',30 phone: '123-456-7890'31 },32 preferences: {33 theme: 'dark',34 notifications: {35 email: true,36 push: false37 }38 }39};4041const {42 personal: { name: fullName, age: years },43 contact: { email: contactEmail },44 preferences: {45 theme,46 notifications: { email: emailNotifications }47 }48} = userProfile;4950// 6. 剩余属性51const settings = {52 theme: 'dark',53 fontSize: 14,54 showLineNumbers: true,55 autoSave: true,56 tabSize: 257};5859const { theme, fontSize, ...otherSettings } = settings;60console.log(otherSettings); 61// { showLineNumbers: true, autoSave: true, tabSize: 2 }6263// 7. 动态属性名64const key = 'dynamicKey';65const obj = { [key]: 'dynamicValue', staticKey: 'staticValue' };66const { [key]: dynamicValue, staticKey } = obj;6768// 8. 函数参数解构69function createUser({ name, age, email = 'unknown' }) {70 return {71 id: Date.now(),72 name,73 age,74 email,75 createdAt: new Date()76 };77}7879const newUser = createUser({ name: 'Bob', age: 25 });8081// 9. 复杂的参数解构82function processApiResponse({83 data: { users = [], posts = [] } = {},84 meta: { page = 1, limit = 10, total = 0 } = {},85 error = null86} = {}) {87 if (error) {88 throw new Error(`API Error: ${error.message}`);89 }90 91 return {92 users: users.slice(0, limit),93 posts: posts.slice(0, limit),94 pagination: { page, limit, total }95 };96}9798// 10. 实际应用示例99// React组件props解构100function UserCard({ 101 user: { name, avatar, email }, 102 onEdit, 103 onDelete,104 className = 'user-card' 105}) {106 return (107 <div className={className}>108 <img src={avatar} alt={name} />109 <h3>{name}</h3>110 <p>{email}</p>111 <button onClick={() => onEdit(user)}>Edit</button>112 <button onClick={() => onDelete(user.id)}>Delete</button>113 </div>114 );115}116117// API数据处理118async function fetchAndProcessUser(userId) {119 const response = await fetch(`/api/users/${userId}`);120 const {121 data: {122 id,123 profile: { firstName, lastName, avatar },124 settings: { theme, language = 'en' },125 stats: { postsCount, followersCount }126 },127 meta: { lastUpdated }128 } = await response.json();129 130 return {131 id,132 fullName: `${firstName} ${lastName}`,133 avatar,134 preferences: { theme, language },135 statistics: { posts: postsCount, followers: followersCount },136 lastUpdated: new Date(lastUpdated)137 };138}139140// 配置对象处理141function initializeApp(config = {}) {142 const {143 api: {144 baseURL = 'http://localhost:3000',145 timeout = 5000,146 retries = 3147 } = {},148 ui: {149 theme = 'light',150 animations = true,151 sidebar = { collapsed: false, width: 250 }152 } = {},153 features: {154 analytics = false,155 notifications = true,156 ...otherFeatures157 } = {}158 } = config;159 160 return {161 apiConfig: { baseURL, timeout, retries },162 uiConfig: { theme, animations, sidebar },163 featureFlags: { analytics, notifications, ...otherFeatures }164 };165}166167// 11. 高级模式168// 条件解构169function processUserData(userData) {170 const isAdmin = userData.role === 'admin';171 172 const {173 name,174 email,175 ...(isAdmin && { 176 adminLevel: adminLevel = 1,177 permissions: permissions = []178 })179 } = userData;180 181 return isAdmin 182 ? { name, email, adminLevel, permissions }183 : { name, email };184}185186// 解构赋值与数组方法结合187const users = [188 { name: 'Alice', age: 25, city: 'New York' },189 { name: 'Bob', age: 30, city: 'London' },190 { name: 'Charlie', age: 35, city: 'Tokyo' }191];192193// 提取特定属性194const names = users.map(({ name }) => name);195const cities = users.map(({ city }) => city);196197// 过滤和解构198const youngUsers = users199 .filter(({ age }) => age < 30)200 .map(({ name, city }) => ({ name, city }));201202// 分组203const usersByCity = users.reduce((acc, { city, ...user }) => {204 acc[city] = acc[city] || [];205 acc[city].push(user);206 return acc;207}, {});扩展运算符应用
扩展运算符完整应用
javascript
1// 1. 数组扩展2const arr1 = [1, 2, 3];3const arr2 = [4, 5, 6];45// 数组合并6const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]7const withExtra = [0, ...arr1, 3.5, ...arr2, 7]; // [0, 1, 2, 3, 3.5, 4, 5, 6, 7]89// 数组复制(浅拷贝)10const copied = [...arr1]; // [1, 2, 3]1112// 数组转换13const str = 'hello';14const chars = [...str]; // ['h', 'e', 'l', 'l', 'o']1516const nodeList = document.querySelectorAll('div');17const divArray = [...nodeList]; // 将NodeList转为数组1819// 2. 对象扩展20const obj1 = { a: 1, b: 2 };21const obj2 = { c: 3, d: 4 };2223// 对象合并24const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }2526// 对象复制(浅拷贝)27const objCopy = { ...obj1 }; // { a: 1, b: 2 }2829// 属性覆盖30const updated = { ...obj1, b: 20, e: 5 }; // { a: 1, b: 20, e: 5 }3132// 3. 函数调用中的扩展33function sum(a, b, c) {34 return a + b + c;35}3637const numbers = [1, 2, 3];38const result = sum(...numbers); // 等同于 sum(1, 2, 3)3940// Math对象方法41const nums = [5, 2, 8, 1, 9];42const max = Math.max(...nums); // 943const min = Math.min(...nums); // 14445// 4. 实用工具函数46// 数组去重47const removeDuplicates = (arr) => [...new Set(arr)];48console.log(removeDuplicates([1, 2, 2, 3, 3, 4])); // [1, 2, 3, 4]4950// 数组扁平化(一层)51const flatten = (arr) => [].concat(...arr);52console.log(flatten([[1, 2], [3, 4], [5]])); // [1, 2, 3, 4, 5]5354// 深度扁平化55const deepFlatten = (arr) => 56 arr.reduce((acc, val) => 57 Array.isArray(val) 58 ? acc.concat(deepFlatten(val))59 : acc.concat(val), 60 []61 );6263// 对象深度合并64const deepMerge = (target, source) => {65 const result = { ...target };66 67 for (const key in source) {68 if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {69 result[key] = deepMerge(result[key] || {}, source[key]);70 } else {71 result[key] = source[key];72 }73 }74 75 return result;76};7778// 5. React中的应用79// 状态更新80const [state, setState] = useState({81 user: { name: 'John', age: 30 },82 settings: { theme: 'dark' }83});8485// 更新嵌套状态86const updateUserAge = (newAge) => {87 setState(prevState => ({88 ...prevState,89 user: {90 ...prevState.user,91 age: newAge92 }93 }));94};9596// Props传递97const UserComponent = (props) => {98 const commonProps = { className: 'user', role: 'button' };99 100 return (101 <div {...commonProps} {...props}>102 {props.children}103 </div>104 );105};106107// 6. 数组操作模式108const todos = [109 { id: 1, text: 'Learn React', completed: false },110 { id: 2, text: 'Build an app', completed: true }111];112113// 添加新项114const addTodo = (newTodo) => [...todos, newTodo];115116// 更新项117const updateTodo = (id, updates) =>118 todos.map(todo => 119 todo.id === id 120 ? { ...todo, ...updates }121 : todo122 );123124// 删除项125const deleteTodo = (id) => todos.filter(todo => todo.id !== id);126127// 7. 高级模式128// 条件扩展129const createUser = (userData, isAdmin = false) => ({130 ...userData,131 role: 'user',132 ...(isAdmin && { 133 role: 'admin',134 permissions: ['read', 'write', 'delete']135 })136});137138// 动态对象构建139const buildApiRequest = (endpoint, options = {}) => ({140 url: endpoint,141 method: 'GET',142 headers: {143 'Content-Type': 'application/json',144 ...options.headers145 },146 ...options147});148149// 函数参数收集150const createLogger = (level, ...formatters) => {151 return (message, ...args) => {152 const formattedMessage = formatters.reduce(153 (msg, formatter) => formatter(msg),154 message155 );156 console[level](formattedMessage, ...args);157 };158};159160const logger = createLogger('log', 161 msg => `[${new Date().toISOString()}]`,162 msg => msg.toUpperCase()163);164165// 8. 性能考虑166// 避免在渲染函数中使用扩展运算符167// 不好的做法168const BadComponent = ({ items }) => (169 <div>170 {[...items].map(item => <Item key={item.id} {...item} />)}171 </div>172);173174// 好的做法175const GoodComponent = ({ items }) => {176 const itemsCopy = useMemo(() => [...items], [items]);177 178 return (179 <div>180 {itemsCopy.map(item => <Item key={item.id} {...item} />)}181 </div>182 );183};184185// 大对象的浅拷贝优化186const optimizedCopy = (obj) => {187 if (Object.keys(obj).length > 1000) {188 // 对于大对象,考虑使用其他方法189 return Object.assign({}, obj);190 }191 return { ...obj };192};4. 模块系统(ES Modules)
4.1 模块导入导出
ES6引入的模块系统提供了标准化的代码组织和复用方式。
- 导入导出语法
- 模块模式
- Tree Shaking优化
模块导入导出详解
模块导出示例
javascript
1// utils.js - 工具函数模块2// 1. 命名导出3export const PI = 3.14159;4export const E = 2.71828;56export function add(a, b) {7 return a + b;8}910export function multiply(a, b) {11 return a * b;12}1314// 批量导出15const subtract = (a, b) => a - b;16const divide = (a, b) => a / b;1718export { subtract, divide };1920// 重命名导出21const power = (base, exponent) => Math.pow(base, exponent);22export { power as pow };2324// 2. 默认导出25class Calculator {26 constructor() {27 this.result = 0;28 }29 30 add(value) {31 this.result += value;32 return this;33 }34 35 subtract(value) {36 this.result -= value;37 return this;38 }39 40 multiply(value) {41 this.result *= value;42 return this;43 }44 45 divide(value) {46 this.result /= value;47 return this;48 }49 50 getValue() {51 return this.result;52 }53 54 reset() {55 this.result = 0;56 return this;57 }58}5960export default Calculator;6162// 同时有命名导出和默认导出63export { Calculator as Calc };模块导入示例
javascript
1// main.js - 主应用文件2// 1. 命名导入3import { add, multiply, PI } from './utils.js';45console.log(add(2, 3)); // 56console.log(multiply(4, 5)); // 207console.log(PI); // 3.1415989// 2. 重命名导入10import { subtract as minus, pow } from './utils.js';1112console.log(minus(10, 3)); // 713console.log(pow(2, 3)); // 81415// 3. 默认导入16import Calculator from './utils.js';1718const calc = new Calculator();19const result = calc.add(10).multiply(2).subtract(5).getValue();20console.log(result); // 152122// 4. 混合导入23import Calculator, { add, PI } from './utils.js';2425// 5. 命名空间导入26import * as MathUtils from './utils.js';2728console.log(MathUtils.add(1, 2)); // 329console.log(MathUtils.PI); // 3.1415930const calculator = new MathUtils.default();3132// 6. 动态导入33async function loadModule() {34 try {35 const module = await import('./utils.js');36 console.log(module.add(1, 2)); // 337 38 const Calculator = module.default;39 const calc = new Calculator();40 console.log(calc.add(5).getValue()); // 541 } catch (error) {42 console.error('模块加载失败:', error);43 }44}4546loadModule();4748// 条件动态导入49async function conditionalImport(condition) {50 if (condition) {51 const { heavyFunction } = await import('./heavy-module.js');52 return heavyFunction();53 }54 return null;55}高级模块模式
高级模块模式
javascript
1// config.js - 配置模块2const config = {3 development: {4 apiUrl: 'http://localhost:3000/api',5 debug: true,6 logLevel: 'debug'7 },8 production: {9 apiUrl: 'https://api.example.com',10 debug: false,11 logLevel: 'error'12 }13};1415const environment = process.env.NODE_ENV || 'development';16export default config[environment];1718// logger.js - 日志模块19class Logger {20 constructor(level = 'info') {21 this.level = level;22 this.levels = {23 debug: 0,24 info: 1,25 warn: 2,26 error: 327 };28 }29 30 log(level, message, ...args) {31 if (this.levels[level] >= this.levels[this.level]) {32 console[level](`[${level.toUpperCase()}]`, message, ...args);33 }34 }35 36 debug(message, ...args) {37 this.log('debug', message, ...args);38 }39 40 info(message, ...args) {41 this.log('info', message, ...args);42 }43 44 warn(message, ...args) {45 this.log('warn', message, ...args);46 }47 48 error(message, ...args) {49 this.log('error', message, ...args);50 }51}5253// 单例模式54let instance = null;5556export function createLogger(level) {57 if (!instance) {58 instance = new Logger(level);59 }60 return instance;61}6263export { Logger };6465// api.js - API模块66import config from './config.js';67import { createLogger } from './logger.js';6869const logger = createLogger(config.logLevel);7071class ApiClient {72 constructor(baseURL = config.apiUrl) {73 this.baseURL = baseURL;74 this.interceptors = {75 request: [],76 response: []77 };78 }79 80 addRequestInterceptor(interceptor) {81 this.interceptors.request.push(interceptor);82 }83 84 addResponseInterceptor(interceptor) {85 this.interceptors.response.push(interceptor);86 }87 88 async request(url, options = {}) {89 let config = {90 ...options,91 url: `${this.baseURL}${url}`,92 headers: {93 'Content-Type': 'application/json',94 ...options.headers95 }96 };97 98 // 应用请求拦截器99 for (const interceptor of this.interceptors.request) {100 config = await interceptor(config);101 }102 103 logger.debug('API请求:', config);104 105 try {106 let response = await fetch(config.url, config);107 108 // 应用响应拦截器109 for (const interceptor of this.interceptors.response) {110 response = await interceptor(response);111 }112 113 if (!response.ok) {114 throw new Error(`HTTP ${response.status}: ${response.statusText}`);115 }116 117 const data = await response.json();118 logger.debug('API响应:', data);119 120 return data;121 } catch (error) {122 logger.error('API请求失败:', error);123 throw error;124 }125 }126 127 get(url, options) {128 return this.request(url, { ...options, method: 'GET' });129 }130 131 post(url, data, options) {132 return this.request(url, {133 ...options,134 method: 'POST',135 body: JSON.stringify(data)136 });137 }138 139 put(url, data, options) {140 return this.request(url, {141 ...options,142 method: 'PUT',143 body: JSON.stringify(data)144 });145 }146 147 delete(url, options) {148 return this.request(url, { ...options, method: 'DELETE' });149 }150}151152// 导出单例实例153export default new ApiClient();154155// 也导出类,允许创建多个实例156export { ApiClient };157158// store.js - 状态管理模块159class Store {160 constructor(initialState = {}) {161 this.state = { ...initialState };162 this.listeners = [];163 this.middlewares = [];164 }165 166 getState() {167 return { ...this.state };168 }169 170 setState(newState) {171 const prevState = { ...this.state };172 this.state = { ...this.state, ...newState };173 174 // 应用中间件175 for (const middleware of this.middlewares) {176 middleware(prevState, this.state);177 }178 179 // 通知监听器180 this.listeners.forEach(listener => {181 listener(this.state, prevState);182 });183 }184 185 subscribe(listener) {186 this.listeners.push(listener);187 188 // 返回取消订阅函数189 return () => {190 const index = this.listeners.indexOf(listener);191 if (index > -1) {192 this.listeners.splice(index, 1);193 }194 };195 }196 197 use(middleware) {198 this.middlewares.push(middleware);199 }200}201202// 创建全局store203const store = new Store({204 user: null,205 theme: 'light',206 language: 'zh-CN'207});208209// 添加日志中间件210store.use((prevState, nextState) => {211 logger.debug('状态变化:', { prevState, nextState });212});213214export default store;215export { Store };216217// app.js - 应用入口218import config from './config.js';219import { createLogger } from './logger.js';220import apiClient from './api.js';221import store from './store.js';222223const logger = createLogger(config.logLevel);224225class App {226 constructor() {227 this.initialized = false;228 }229 230 async init() {231 if (this.initialized) return;232 233 logger.info('应用初始化开始');234 235 try {236 // 设置API拦截器237 apiClient.addRequestInterceptor(async (config) => {238 const token = store.getState().user?.token;239 if (token) {240 config.headers.Authorization = `Bearer ${token}`;241 }242 return config;243 });244 245 // 加载用户信息246 await this.loadUser();247 248 // 订阅状态变化249 store.subscribe((state, prevState) => {250 if (state.theme !== prevState.theme) {251 this.updateTheme(state.theme);252 }253 });254 255 this.initialized = true;256 logger.info('应用初始化完成');257 258 } catch (error) {259 logger.error('应用初始化失败:', error);260 throw error;261 }262 }263 264 async loadUser() {265 try {266 const user = await apiClient.get('/user/profile');267 store.setState({ user });268 } catch (error) {269 logger.warn('用户信息加载失败:', error);270 }271 }272 273 updateTheme(theme) {274 document.documentElement.setAttribute('data-theme', theme);275 logger.info('主题已更新:', theme);276 }277 278 async login(credentials) {279 try {280 const response = await apiClient.post('/auth/login', credentials);281 store.setState({ user: response.user });282 logger.info('用户登录成功');283 return response;284 } catch (error) {285 logger.error('登录失败:', error);286 throw error;287 }288 }289 290 logout() {291 store.setState({ user: null });292 logger.info('用户已登出');293 }294}295296export default new App();Tree Shaking与模块优化
Tree Shaking优化示例
javascript
1// utils/math.js - 数学工具函数2export const add = (a, b) => a + b;3export const subtract = (a, b) => a - b;4export const multiply = (a, b) => a * b;5export const divide = (a, b) => a / b;6export const power = (base, exp) => Math.pow(base, exp);7export const sqrt = (n) => Math.sqrt(n);89// 复杂函数,可能不会被使用10export const complexCalculation = (data) => {11 // 大量计算逻辑12 return data.reduce((acc, val) => acc + val * val, 0);13};1415// utils/string.js - 字符串工具函数16export const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);17export const camelCase = (str) => str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());18export const kebabCase = (str) => str.replace(/([A-Z])/g, '-$1').toLowerCase();19export const truncate = (str, length) => str.length > length ? str.slice(0, length) + '...' : str;2021// 大型工具函数,可能不会被使用22export const advancedStringProcessing = (str) => {23 // 复杂的字符串处理逻辑24 return str.split('').reverse().join('').toUpperCase();25};2627// utils/index.js - 统一导出(避免这种做法,不利于Tree Shaking)28// 不推荐的做法29export * from './math.js';30export * from './string.js';3132// 推荐的做法 - 明确导出需要的函数33export { add, subtract, multiply, divide } from './math.js';34export { capitalize, camelCase, kebabCase } from './string.js';3536// main.js - 主应用文件37// Tree Shaking友好的导入方式38import { add, multiply } from './utils/math.js';39import { capitalize } from './utils/string.js';4041// 只有这些函数会被包含在最终的bundle中42console.log(add(2, 3)); // 543console.log(multiply(4, 5)); // 2044console.log(capitalize('hello')); // "Hello"4546// 动态导入优化47async function loadHeavyModule() {48 // 只在需要时加载大型模块49 const { heavyFunction } = await import('./heavy-module.js');50 return heavyFunction();51}5253// 条件加载54if (process.env.NODE_ENV === 'development') {55 import('./dev-tools.js').then(devTools => {56 devTools.init();57 });58}5960// webpack.config.js - Webpack配置示例61module.exports = {62 mode: 'production', // 启用Tree Shaking63 optimization: {64 usedExports: true, // 标记未使用的导出65 sideEffects: false, // 声明代码无副作用66 // 或者指定有副作用的文件67 // sideEffects: ['*.css', './src/polyfills.js']68 },69 resolve: {70 // 优先使用ES模块版本71 mainFields: ['module', 'main']72 }73};7475// package.json - 包配置76{77 "name": "my-package",78 "version": "1.0.0",79 "main": "dist/index.js",80 "module": "dist/index.esm.js", // ES模块版本81 "sideEffects": false, // 声明包无副作用82 "exports": {83 ".": {84 "import": "./dist/index.esm.js",85 "require": "./dist/index.js"86 },87 "./math": {88 "import": "./dist/math.esm.js",89 "require": "./dist/math.js"90 }91 }92}9394// 模块分析工具95class BundleAnalyzer {96 static analyzeImports(code) {97 const importRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;98 const imports = [];99 let match;100 101 while ((match = importRegex.exec(code)) !== null) {102 imports.push(match[1]);103 }104 105 return imports;106 }107 108 static findUnusedExports(exports, imports) {109 return exports.filter(exp => !imports.includes(exp));110 }111 112 static generateReport(modules) {113 const report = {114 totalModules: modules.length,115 unusedExports: [],116 circularDependencies: [],117 bundleSize: 0118 };119 120 // 分析逻辑121 modules.forEach(module => {122 // 检查未使用的导出123 // 检查循环依赖124 // 计算bundle大小125 });126 127 return report;128 }129}5. 类与继承
5.1 ES6类语法
ES6引入的class语法提供了更清晰的面向对象编程方式。
- 类基础
- 继承
- 高级模式
类的基本语法
ES6类详解
javascript
1// 基础类定义2class Person {3 // 静态属性4 static species = 'Homo sapiens';5 6 // 私有字段(ES2022)7 #id = Math.random().toString(36);8 9 // 构造函数10 constructor(name, age) {11 this.name = name;12 this.age = age;13 this._email = ''; // 约定的私有属性14 }15 16 // 实例方法17 introduce() {18 return `Hello, I'm ${this.name}, ${this.age} years old.`;19 }20 21 // Getter22 get email() {23 return this._email;24 }25 26 // Setter27 set email(value) {28 if (this.validateEmail(value)) {29 this._email = value;30 } else {31 throw new Error('Invalid email format');32 }33 }34 35 // 私有方法36 #generateId() {37 return Math.random().toString(36).substr(2, 9);38 }39 40 // 公共方法调用私有方法41 getId() {42 return this.#id;43 }44 45 // 静态方法46 static createFromString(str) {47 const [name, age] = str.split(',');48 return new Person(name.trim(), parseInt(age.trim()));49 }50 51 static compareAge(person1, person2) {52 return person1.age - person2.age;53 }54 55 // 验证方法56 validateEmail(email) {57 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;58 return emailRegex.test(email);59 }60 61 // 转换为JSON62 toJSON() {63 return {64 name: this.name,65 age: this.age,66 email: this._email67 };68 }69 70 // 字符串表示71 toString() {72 return `Person(${this.name}, ${this.age})`;73 }74}7576// 使用类77const person1 = new Person('Alice', 25);78console.log(person1.introduce()); // "Hello, I'm Alice, 25 years old."7980person1.email = 'alice@example.com';81console.log(person1.email); // "alice@example.com"8283console.log(person1.getId()); // 私有ID8485// 静态方法使用86const person2 = Person.createFromString('Bob, 30');87console.log(Person.compareAge(person1, person2)); // -58889console.log(Person.species); // "Homo sapiens"类继承详解
类继承示例
javascript
1// 基类2class Animal {3 constructor(name, species) {4 this.name = name;5 this.species = species;6 this.energy = 100;7 }8 9 eat(food) {10 console.log(`${this.name} is eating ${food}`);11 this.energy += 10;12 }13 14 sleep() {15 console.log(`${this.name} is sleeping`);16 this.energy += 20;17 }18 19 move() {20 console.log(`${this.name} is moving`);21 this.energy -= 5;22 }23 24 getStatus() {25 return `${this.name} (${this.species}) - Energy: ${this.energy}`;26 }27}2829// 继承类30class Dog extends Animal {31 constructor(name, breed) {32 super(name, 'Canine'); // 调用父类构造函数33 this.breed = breed;34 this.tricks = [];35 }36 37 // 重写父类方法38 move() {39 console.log(`${this.name} is running`);40 this.energy -= 3; // 狗跑步消耗更少能量41 }42 43 // 新增方法44 bark() {45 console.log(`${this.name} says: Woof!`);46 this.energy -= 2;47 }48 49 learnTrick(trick) {50 this.tricks.push(trick);51 console.log(`${this.name} learned ${trick}`);52 }53 54 performTrick(trick) {55 if (this.tricks.includes(trick)) {56 console.log(`${this.name} performs ${trick}`);57 this.energy -= 5;58 } else {59 console.log(`${this.name} doesn't know ${trick}`);60 }61 }62 63 // 重写getStatus方法64 getStatus() {65 const baseStatus = super.getStatus(); // 调用父类方法66 return `${baseStatus} - Breed: ${this.breed} - Tricks: ${this.tricks.length}`;67 }68}6970// 多层继承71class ServiceDog extends Dog {72 constructor(name, breed, certification) {73 super(name, breed);74 this.certification = certification;75 this.isWorking = false;76 }77 78 startWork() {79 this.isWorking = true;80 console.log(`${this.name} is now working`);81 }82 83 stopWork() {84 this.isWorking = false;85 console.log(`${this.name} is off duty`);86 }87 88 // 重写move方法89 move() {90 if (this.isWorking) {91 console.log(`${this.name} is carefully guiding`);92 this.energy -= 2;93 } else {94 super.move(); // 调用父类的move方法95 }96 }97 98 getStatus() {99 const baseStatus = super.getStatus();100 return `${baseStatus} - Certification: ${this.certification} - Working: ${this.isWorking}`;101 }102}103104// 使用继承105const dog = new Dog('Buddy', 'Golden Retriever');106dog.eat('kibble');107dog.bark();108dog.learnTrick('sit');109dog.learnTrick('fetch');110dog.performTrick('sit');111console.log(dog.getStatus());112113const serviceDog = new ServiceDog('Max', 'German Shepherd', 'Guide Dog');114serviceDog.startWork();115serviceDog.move();116serviceDog.stopWork();117serviceDog.move();118console.log(serviceDog.getStatus());119120// Mixin模式 - 多重继承的替代方案121const Flyable = {122 fly() {123 console.log(`${this.name} is flying`);124 this.energy -= 10;125 },126 127 land() {128 console.log(`${this.name} has landed`);129 }130};131132const Swimmable = {133 swim() {134 console.log(`${this.name} is swimming`);135 this.energy -= 8;136 },137 138 dive() {139 console.log(`${this.name} is diving`);140 this.energy -= 12;141 }142};143144// 应用Mixin145class Bird extends Animal {146 constructor(name, species) {147 super(name, species);148 }149}150151// 将Mixin混入到类中152Object.assign(Bird.prototype, Flyable);153154class Duck extends Bird {155 constructor(name) {156 super(name, 'Duck');157 }158}159160// 鸭子既能飞又能游泳161Object.assign(Duck.prototype, Flyable, Swimmable);162163const duck = new Duck('Donald');164duck.fly();165duck.swim();166duck.dive();167duck.land();168169// 抽象类模拟170class AbstractShape {171 constructor() {172 if (new.target === AbstractShape) {173 throw new Error('Cannot instantiate abstract class');174 }175 }176 177 // 抽象方法178 getArea() {179 throw new Error('Abstract method must be implemented');180 }181 182 getPerimeter() {183 throw new Error('Abstract method must be implemented');184 }185 186 // 具体方法187 describe() {188 return `This shape has an area of ${this.getArea()} and perimeter of ${this.getPerimeter()}`;189 }190}191192class Rectangle extends AbstractShape {193 constructor(width, height) {194 super();195 this.width = width;196 this.height = height;197 }198 199 getArea() {200 return this.width * this.height;201 }202 203 getPerimeter() {204 return 2 * (this.width + this.height);205 }206}207208class Circle extends AbstractShape {209 constructor(radius) {210 super();211 this.radius = radius;212 }213 214 getArea() {215 return Math.PI * this.radius * this.radius;216 }217 218 getPerimeter() {219 return 2 * Math.PI * this.radius;220 }221}222223// 使用抽象类224const rectangle = new Rectangle(5, 3);225console.log(rectangle.describe()); // "This shape has an area of 15 and perimeter of 16"226227const circle = new Circle(4);228console.log(circle.describe()); // "This shape has an area of 50.26... and perimeter of 25.13..."229230// 尝试实例化抽象类会抛出错误231// const shape = new AbstractShape(); // Error: Cannot instantiate abstract class高级类模式
高级类模式示例
javascript
1// 1. 装饰器模式(使用类)2class Component {3 operation() {4 return 'Component';5 }6}78class Decorator extends Component {9 constructor(component) {10 super();11 this.component = component;12 }13 14 operation() {15 return this.component.operation();16 }17}1819class ConcreteDecoratorA extends Decorator {20 operation() {21 return `ConcreteDecoratorA(${super.operation()})`;22 }23}2425class ConcreteDecoratorB extends Decorator {26 operation() {27 return `ConcreteDecoratorB(${super.operation()})`;28 }29}3031// 使用装饰器32let component = new Component();33component = new ConcreteDecoratorA(component);34component = new ConcreteDecoratorB(component);35console.log(component.operation()); // "ConcreteDecoratorB(ConcreteDecoratorA(Component))"3637// 2. 观察者模式38class EventEmitter {39 constructor() {40 this.events = {};41 }42 43 on(event, listener) {44 if (!this.events[event]) {45 this.events[event] = [];46 }47 this.events[event].push(listener);48 }49 50 off(event, listenerToRemove) {51 if (!this.events[event]) return;52 53 this.events[event] = this.events[event].filter(54 listener => listener !== listenerToRemove55 );56 }57 58 emit(event, ...args) {59 if (!this.events[event]) return;60 61 this.events[event].forEach(listener => {62 listener.apply(this, args);63 });64 }65 66 once(event, listener) {67 const onceListener = (...args) => {68 listener.apply(this, args);69 this.off(event, onceListener);70 };71 this.on(event, onceListener);72 }73}7475class Model extends EventEmitter {76 constructor(data = {}) {77 super();78 this.data = { ...data };79 }80 81 set(key, value) {82 const oldValue = this.data[key];83 this.data[key] = value;84 this.emit('change', key, value, oldValue);85 this.emit(`change:${key}`, value, oldValue);86 }87 88 get(key) {89 return this.data[key];90 }91 92 toJSON() {93 return { ...this.data };94 }95}9697// 使用观察者模式98const model = new Model({ name: 'John', age: 25 });99100model.on('change', (key, newValue, oldValue) => {101 console.log(`${key} changed from ${oldValue} to ${newValue}`);102});103104model.on('change:name', (newValue, oldValue) => {105 console.log(`Name specifically changed from ${oldValue} to ${newValue}`);106});107108model.set('name', 'Jane'); // 触发两个事件109model.set('age', 26); // 触发change事件110111// 3. 单例模式112class Singleton {113 constructor() {114 if (Singleton.instance) {115 return Singleton.instance;116 }117 118 this.data = {};119 Singleton.instance = this;120 }121 122 static getInstance() {123 if (!Singleton.instance) {124 Singleton.instance = new Singleton();125 }126 return Singleton.instance;127 }128 129 setData(key, value) {130 this.data[key] = value;131 }132 133 getData(key) {134 return this.data[key];135 }136}137138// 使用单例139const singleton1 = new Singleton();140const singleton2 = new Singleton();141const singleton3 = Singleton.getInstance();142143console.log(singleton1 === singleton2); // true144console.log(singleton2 === singleton3); // true145146singleton1.setData('test', 'value');147console.log(singleton2.getData('test')); // 'value'148149// 4. 工厂模式150class Product {151 constructor(name) {152 this.name = name;153 }154}155156class ConcreteProductA extends Product {157 constructor() {158 super('Product A');159 }160 161 operation() {162 return 'ConcreteProductA operation';163 }164}165166class ConcreteProductB extends Product {167 constructor() {168 super('Product B');169 }170 171 operation() {172 return 'ConcreteProductB operation';173 }174}175176class ProductFactory {177 static createProduct(type) {178 switch (type) {179 case 'A':180 return new ConcreteProductA();181 case 'B':182 return new ConcreteProductB();183 default:184 throw new Error('Unknown product type');185 }186 }187}188189// 使用工厂模式190const productA = ProductFactory.createProduct('A');191const productB = ProductFactory.createProduct('B');192193console.log(productA.operation()); // "ConcreteProductA operation"194console.log(productB.operation()); // "ConcreteProductB operation"195196// 5. 建造者模式197class User {198 constructor() {199 this.name = '';200 this.email = '';201 this.age = 0;202 this.address = '';203 this.phone = '';204 }205}206207class UserBuilder {208 constructor() {209 this.user = new User();210 }211 212 setName(name) {213 this.user.name = name;214 return this;215 }216 217 setEmail(email) {218 this.user.email = email;219 return this;220 }221 222 setAge(age) {223 this.user.age = age;224 return this;225 }226 227 setAddress(address) {228 this.user.address = address;229 return this;230 }231 232 setPhone(phone) {233 this.user.phone = phone;234 return this;235 }236 237 build() {238 return this.user;239 }240}241242// 使用建造者模式243const user = new UserBuilder()244 .setName('John Doe')245 .setEmail('john@example.com')246 .setAge(30)247 .setAddress('123 Main St')248 .setPhone('555-1234')249 .build();250251console.log(user);252253// 6. 策略模式254class Strategy {255 execute(data) {256 throw new Error('Strategy execute method must be implemented');257 }258}259260class ConcreteStrategyA extends Strategy {261 execute(data) {262 return data.sort((a, b) => a - b); // 升序排序263 }264}265266class ConcreteStrategyB extends Strategy {267 execute(data) {268 return data.sort((a, b) => b - a); // 降序排序269 }270}271272class ConcreteStrategyC extends Strategy {273 execute(data) {274 return data.filter(item => item % 2 === 0); // 过滤偶数275 }276}277278class Context {279 constructor(strategy) {280 this.strategy = strategy;281 }282 283 setStrategy(strategy) {284 this.strategy = strategy;285 }286 287 executeStrategy(data) {288 return this.strategy.execute(data);289 }290}291292// 使用策略模式293const data = [5, 2, 8, 1, 9, 3];294const context = new Context(new ConcreteStrategyA());295296console.log(context.executeStrategy([...data])); // [1, 2, 3, 5, 8, 9]297298context.setStrategy(new ConcreteStrategyB());299console.log(context.executeStrategy([...data])); // [9, 8, 5, 3, 2, 1]300301context.setStrategy(new ConcreteStrategyC());302console.log(context.executeStrategy([...data])); // [2, 8]面试题
1. let、const和var的区别是什么?
答案:
- 作用域:var是函数作用域,let和const是块级作用域
- 变量提升:var会提升并初始化为undefined,let和const会提升但不初始化(暂时性死区)
- 重复声明:var允许重复声明,let和const不允许
- 重新赋值:var和let可以重新赋值,const不可以
- 全局对象属性:var声明的全局变量会成为全局对象的属性,let和const不会
2. 箭头函数与普通函数的区别?
答案:
- this绑定:箭头函数没有自己的this,继承外层作用域的this;普通函数的this由调用方式决定
- arguments对象:箭头函数没有arguments对象,普通函数有
- 构造函数:箭头函数不能作为构造函数,普通函数可以
- 原型:箭头函数没有prototype属性,普通函数有
- yield关键字:箭头函数不能使用yield,不能作为生成器函数
3. 什么是解构赋值?有哪些应用场景?
答案: 解构赋值是一种JavaScript表达式,可以将数组或对象的属性解包到不同的变量中。
应用场景:
- 交换变量:
[a, b] = [b, a] - 函数参数:
function({name, age}) {} - 提取数组元素:
const [first, second] = array - 提取对象属性:
const {name, age} = person - 设置默认值:
const {name = 'Unknown'} = person
4. ES6模块与CommonJS模块的区别?
答案:
- 加载时机:ES6模块是编译时加载,CommonJS是运行时加载
- 输出:ES6模块输出的是值的引用,CommonJS输出的是值的拷贝
- this指向:ES6模块顶层this是undefined,CommonJS顶层this指向当前模块
- 循环依赖:ES6模块支持循环依赖,CommonJS可能出现问题
- Tree Shaking:ES6模块支持静态分析,可以进行Tree Shaking优化
5. 什么是Promise?如何处理Promise链?
答案: Promise是异步编程的解决方案,代表一个异步操作的最终完成或失败。
Promise有三种状态:
- pending(进行中)
- fulfilled(已成功)
- rejected(已失败)
Promise链处理:
javascript
1promise2 .then(result => {3 // 处理成功结果4 return nextPromise;5 })6 .then(result => {7 // 处理下一个结果8 })9 .catch(error => {10 // 处理错误11 })12 .finally(() => {13 // 无论成功失败都执行14 });通过掌握这些ES6+特性,可以编写更现代、更简洁、更强大的JavaScript代码,提升开发效率和代码质量。
参与讨论