1. 控制台console的使用使用场景 改进调试复杂对象的日志记录。console.table、console.group 和 console.time 等控制台方法可以提供更结构化、更 informative 的调试信息。// 基本日志记录console.log(简单日志);console.error(这是一个错误);console.warn(这是一个警告);//记录表格数据const users [{ name: John, age: 30, city: New York },{ name: Jane, age: 25, city: San Francisco },];console.table(users);//分组日志console.group(用户详细信息);console.log(用户 1: John);console.log(用户 2: Jane);console.groupEnd();//计时代码执行console.time(计时器);for (let i 0; i 1000000; i) {//一些繁重的计算}console.timeEnd(计时器);2. 不使用临时变量来交换变量的值例如我们想要将 a 于 b 的值交换let a 1, b 2;//交换值[a, b] [b, a];//结果: a 2, b 1这行代码使用数组解构赋值的方式来交换两个变量的值3. 浅克隆对象const originalObj { name: 张三, age: 24 };const clonedObj { ...originalObj };//结果: clonedObj { name: 张三, age: 24 }//此时改变 clonedObj 的属性将不会影响到原始对象 originalObj通过使用扩展运算符 (...) 创建originalObj的浅克隆对象。4. 合并对象const obj1 { name: 张三 };const obj2 { age: 22 };const mergedObj { ...obj1, ...obj2 };//结果: mergedObj { name: 张三, age: 22 }与克隆类似通过扩展运算符将obj1和合并obj2为一个新的对象。如果有重叠的属性则最后一个对象的属性将覆盖前一个对象的属性。5. find和findIndex的使用需要找到第一个满足特定条件的元素find()是你的救星。它会返回第一个通过回调函数测试的元素的值非常适合快速查找和避免遍历整个数组。示例 找到第一个大于3的元素const numbers [1, 2, 4, 5];const firstGreaterThanThree numbers.find(number number 3);console.log(firstGreaterThanThree);//输出: 4findIndex()比find()更进一步它会返回第一个通过回调函数测试的元素的索引。这在查找数组中的特定数据、根据元素在数组中的位置修改元素以及执行针对性的操作时非常有用。示例 找到第一个大于3的元素的索引const numbers [1, 2, 4, 5];const indexOfFirstGreaterThanThree numbers.findIndex(number number 3);console.log(indexOfFirstGreaterThanThree);//输出: 26. 将 NodeList 转换为数组const nodesArray [ ...document.querySelectorAll(div) ];通过扩展运算符将NodeList( document.querySelectorAll函数的返回值) 转换为 JavaScript 数组从而能够使用数组的map方法filter去操作查找到的元素。7. forEach遍历数组forEach()就像一位可靠的助手可以遍历数组中的每个元素并执行你指定的任务。它接受一个回调函数该函数会对每个元素执行操作非常适合处理副作用例如日志记录、DOM操作和数据修改。示例 打印数组中的所有元素const fruits [apple, banana, cherry];fruits.forEach(fruit console.log(fruit));8. 数组去重复项const arr [1, 2, 2, 3, 4, 4, 5];const unique [...newSet(arr)];//结果: unique [1, 2, 3, 4, 5]这里利用了Set对象存储的值会保持唯一以及扩展运算符能将Set转换回数组的特性。这是一种优雅的删除数组中重复项的方式。9. 根据指定条件判断是否给对象的属性赋值const condition true;const value 你好世界;//如果条件为真则将 value 变量的值赋给 newObject.key 属性const newObject {...(condition {key: value})};//结果: newObject { key: 你好世界 }此案例使用扩展运算符 (...) 与短路求值()将属性有条件地添加到对象中。 如果condition为真则会将{key: value}扩展到对象中否则不进行任何操作。10. 使用变量作为对象的键const dynamicKey name;const value 张三;//使用一个动态的变量作为 keyconst obj {[dynamicKey]: value};//结果: obj { name: 张三 }这种语法称为计算属性名它允许使用变量作为对象的键。方括号内的dynamicKey表达式会计算其值以将其用作属性名称。11. 离线状态检查器const isOnline navigator.onLine ? 在线 : 离线;//结果: isOnline 在线 或 离线这段代码使用三元运算符检查浏览器的在线状态(navigator.onLine)如果为真则返回在线否则返回离线。这是一种动态检查用户网络连接状态的方法。12. 将 url 问号后面的查询字符串转为对象const query nameJohnage30;//将字符串解析为对象const parseQuery query Object.fromEntries(new URLSearchParams(query));//结果: parseQuery { name: John, age: 30 }此示例将一个查询字符串转换为了一个对象。其中URLSearchParams会进行字符串解析它将返回一个可迭代对象然后在通过Object.fromEntries将它转换为对象从而使 URL 参数检索变得方便多了。13. 将秒数转换为时间格式的字符串const seconds 3661;//一小时是 3600 秒多出 61 秒const toTimeString seconds newDate(seconds*1000).toISOString().substr(11, 8);toTimeString(seconds));//结果: 01:01:01此示例将秒数转换为 HH:MM:SS 格式的字符串。它通过给定的秒数加上时间戳起始点来创建一个新的 Date 对象然后将其转换为 ISO 字符串并提取时间部分得到结果。14. 求某对象所有属性值的最大值// 数学、语文、英语成绩const scores { math: 95, chinese: 99, english: 88 };const maxObjectValue obj Math.max(...Object.values(obj));//最高分maxObjectValue(scores));//结果: 99此示例用于在对象所有的属性值中找到最大值。其中Object.values(obj)将对象所有的属性值提取为数组然后使用展开运算符将数组的所有元素作为Math.max函数的参数进行最大值查找。15. 判断对象的值中是否包含有某个值const person { name: 张三, age: 30 };const hasValue (obj, value) Object.values(obj).includes(value);hasValue(person, 30);//结果: truehasValue函数会检查对象的值中是否存在指定的值。其中Object.values(obj)用于获取对象中所有的值的数组然后通过includes(value)检查指定值是否在该数组中。16. 安全访问深度嵌套的对象属性const user { profile: { name: 张三 } };const userName user.profile?.name ?? 匿名;//结果: userName 张三此代码首先演示了如何使用可选链运算符 (?.) 安全地访问user.profile的name值。如果user.profile是undefined或null它会短路并返回undefined从而避免潜在的类型错误TypeError。然后使用空值合并运算符 (??) 检查左侧是否为null或undefined如果是则使用默认值匿名。这可确保后备值不会是其他假值(如或0)。这对于访问数据结构中可能不存在某些中间属性的深层嵌套属性非常有用。在 JavaScript 中空值合并运算符 (??) 和逻辑或 (||) 都可以用于提供默认值但它们处理假值的方式有所不同。在上面的例子中如果把??改为||行为会稍微有些不同。||的左侧如果为假值它将会返回右侧的值。JavaScript 中的假值包括null、undefined、0、NaN、(空字符串)和false。这意味着||左边的值不仅仅是null或undefined如果还是其他假值那么都将返回右侧的值。17. 条件执行语句const isEligible true;isEligible performAction();//如果 isEligible 为真则调用 performAction()利用逻辑 AND ( ) 运算符函数performAction()仅会在isEligible结果为true时执行。这是一种无需if语句即可有条件地执行函数的简介语法。这对于根据某些条件执行函数非常有用尤其是在事件处理或回调中。如果想要条件赋值则可以这样写const isEligible true;let value ;//需要将赋值语句用用括号括起来isEligible (value 条件达成);//如果 isEligible 为真则执行 (value 条件达成) 语句18. 创建包含值为指定数字范围的数组例如创建数字5以内所有正数的数组const range Array.from({ length: 5 }, (_, i) i 1);//结果: range [1, 2, 3, 4, 5]Array.from()从类数组或可迭代对象创建一个新数组。这里它接受一个具有属性length和映射函数的对象。映射函数 ( (_, i) i 1) 使用索引 ( i) 生成从 1 到 5 的数字。下划线 ( _) 是一种惯例表示未使用该参数。19. 提取文件扩展名const fileName example.png;const getFileExtension str str.slice(((str.lastIndexOf(.) - 1) 0) 2);//结果: getFileExtension png这个案例实现了从字符串中提取文件扩展名。它先找到最后一次出现点号 (.) 位置然后截取从该位置到末尾的字符串。位运算符 () 确保了即使未找到点号 (.) 操作也是安全的因为在这种情况下仍然会返回一个空字符串。20. 切换元素的 classconst element document.querySelector(.my-element);const toggleClass (el, className) el.classList.toggle(className);toggleClass(element, active);toggleClass函数使用classList.toggle()方法从一个元素的 class 列表中添加或移除某个 class。如果该 class 存在则删除否则添加。这是一种根据用户交互或应用程序状态动态更新 class 的方法。非常适合实现响应式设计元素例如菜单根据用户操作显示或隐藏。21. 数组的map方法需要根据现有数组创建一个新的数组并进行一些修改map()可以帮到你。它会根据回调函数对每个元素进行操作并返回一个包含结果的新数组。它非常适合提取数据集、提供数据和执行计算。示例 将数组中的每个数字翻倍const numbers [1, 2, 3, 4];const doubledNumbers numbers.map(number number * 2);console.log(doubledNumbers);//输出 [2, 4, 6, 8]22. 数组的filter方法想象一下有人在门口把守只允许特定的人进入VIP区域。 filter()的功能类似它会创建一个新数组只包含通过回调函数测试的元素。你可以用它根据条件筛选数据、删除不需要的元素或创建自定义子集。示例 从数组中获取偶数const numbers [1, 2, 3, 4, 5];const evenNumbers numbers.filter(number number % 2 0);console.log(evenNumbers);//输出 [2, 4]23. 数组的reduce方法reduce()就像一位武林高手可以将整个数组整合为一个单一的值并使用回调函数进行操作。它非常灵活可以计算总和、平均值找到最大值和最小值甚至创建复杂的数据结构。示例 计算数组的总和const numbers [1, 2, 3, 4];const sum numbers.reduce((accumulator, current) accumulator current, 0);console.log(sum);//输出: 1024. 数组的some方法你是否需要检查数组中是否存在至少一个满足特定条件的元素some()可以帮到你。它会检查是否存在至少一个元素通过回调函数测试。你可以用它来确认条件、验证输入或者在只需要一个匹配元素时简化逻辑。示例 检查数组中是否存在大于10的元素const numbers [1, 5, 8, 12];const hasElementGreaterThanTen numbers.some(number number 10);console.log(hasElementGreaterThanTen);//输出: true25. 数组的every方法every()是some()的严格的兄长。它会确保数组中的所有元素都通过回调函数测试。这对于数据验证、检查所有元素是否符合指定结构以及进行质量检查非常有用。示例 检查数组中的所有元素是否都是字符串const data [apple, banana, 10];const allStrings data.every(element typeof element string);console.log(allStrings);//输出: false26. 数组的includes方法有时你只需要知道数组中是否存在特定值。 includes()是进行简单验证的最佳助手。它会快速检查给定值是否存在于数组中这对于识别单个数据点或根据数组成员资格创建条件逻辑非常重要。示例 检查数组中是否包含值 orangeconst fruits [apple, banana, cherry];const hasOrange fruits.includes(orange);console.log(hasOrange);//输出: false27. 数组的flat方法你是否遇到过多维数组或数组嵌套在数组中的情况它们可能很混乱。flat()可以将它们转换为一维数组。这对于简化嵌套数组、处理可能具有嵌套结构的API数据以及存储数据以便进一步处理非常有用。示例 扁平化嵌套数组const nestedArray [1, [2, 3], 4];const flattenedArray nestedArray.flat();console.log(flattenedArray);//输出: [1, 2, 3, 4]提示 考虑使用flatMap()这是JavaScript的另一个新功能它可以让你更好地控制扁平化和转换操作。28. 记忆化记忆化是一种优化技术它涉及缓存昂贵函数调用的结果并在再次出现相同输入时返回缓存的结果。这可以显著提高计算量大的函数的性能特别是那些频繁使用相同参数调用的函数。使用场景 提高递归函数(如斐波那契数列计算)的性能。如果没有记忆化对斐波那契函数的每次调用都会多次冗余地计算相同的值导致时间复杂度呈指数级增长。const memoize (fn) { const cache {}; return (...args) { const key JSON.stringify(args); if (!cache[key]) { cache[key] fn(...args); } return cache[key]; };};const fibonacci memoize((n) { if (n 1) return n; return fibonacci(n - 1) fibonacci(n - 2);});console.log(fibonacci(40)); // 102334155为什么要用它 避免冗余计算显著提高具有重复输入的函数的性能。记忆化可以将低效的重复计算转换为可管理的线性时间操作使其成为优化性能密集型任务的必要技术。29. Proxy 代理Proxy 对象允许你为另一个对象创建代理使你能够拦截和重新定义基本操作例如属性查找、赋值、枚举、函数调用等。这提供了一种强大的方式来向对象添加自定义行为。使用场景 在对象属性访问和赋值时进行验证和日志记录。例如你可以强制执行类型约束并记录访问尝试从而提供更好的控制和调试功能。const user { name: John, age: 30};const handler { get: (target, prop) { console.log(Getting ${prop}); return target[prop]; }, set: (target, prop, value) { if (prop age typeof value ! number) { throw new TypeError(Age must be a number); } console.log(Setting ${prop} to ${value}); target[prop] value; return true; }};const proxyUser new Proxy(user, handler);console.log(proxyUser.name); // Getting name, JohnproxyUser.age 35; // Setting age to 35// proxyUser.age 35; // Throws TypeError为什么要用它 允许为对象操作(例如验证、日志记录等)自定义行为从而增强对对象操作的控制。代理还可以用于实现复杂的逻辑例如访问控制和数据绑定。这使得它们成为管理和扩展对象行为的多功能工具。