学习如何使用简洁高效的高级 JavaScript 语法实现复杂的逻辑。
1. 无需临时变量交换值
let a = 1, b = 2;
[ ] = [b, a];
// Output: a = 2, b = 1
这个单行代码使用了数组解构来在不使用临时变量的情况下交换 a 和 b 的值。这是一个巧妙的技巧,使您的代码更干净、更简洁。[a, b] = [b, a] 语法通过在右侧解构数组并将其分配给左侧来交换它们的值。
2. 对象解构:更便捷的数据访问
const {name, age} = {name: 'John', age: 30};
// Output: name = 'John', age = 30
在这里,对象解构被用来直接从对象中提取出 name 和 age 属性并将其赋值给变量。这种方法简化了访问对象属性的过程,并提高了代码的可读性。
3. 快速克隆对象
const originalObj = {name: 'Jane', age: 22};
const clonedObj = {...originalObj};
// Output: clonedObj = {name: 'Jane', age: 22}
扩展运算符( … )用于创建 originalObj 的一个浅层克隆。该技术会将原始对象的所有枚举属性复制到一个新的对象中。
那么我们为什么不能直接将旧对象赋值给新对象呢?
const clonedObj = originalObj;
clonedObj.name = "George";
// Output: originalObj = {name: 'George', age: 22}
你可以这样做,但是 clonedObj 只会成为 originalObj 的一个引用,所以如果你尝试修改 name 的属性,实际上是在修改 originalObj !
4. 合并对象,轻松搞定!
const obj1 = {name: 'Jane'};
const obj2 = {age: 22};
const mergedObj = {...obj1, ...obj2};
// Output: mergedObj = {name: 'Jane', age: 22}
与克隆类似,扩展运算符用于将 obj1 和 obj2 合并成一个新的对象。如果有重叠的属性,则最后对象的属性将覆盖先前的属性。
5. 清理数组
const arr = [0, 1, false, 2, '', 3];
const cleanedArray = arr.filter(Boolean);
// Output: cleanedArray = [1, 2, 3]
这个巧妙的技巧与 Boolean 构造函数一起使用 Array.prototype.filter() 作为回调。它从数组中删除所有虚假值 ( 0 , false , null , undefined NaN , ” , )。
6. 将 NodeList 转换为数组
const nodesArray = [...document.querySelectorAll('div')];
扩展运算符用于将一个(由 document.querySelectorAll 返回的)对象转换为JavaScript数组,从而使数组方法(如 map 、 filter 等)得以使用。
7. 检查数组是否满足特定条件
const arr = [1, 2, 3, -1, 4];
const hasNegativeNumbers = arr.some(num => num < 0);
// Output: hasNegativeNumbers = true
`hasNegativeNumbers` 方法检查数组中至少有一个元素通过由提供的函数(此处为负数)执行的测试,而 `allPositive` 方法检查所有元素都通过了测试(为正数)。
const arr = [1, 2, 3, -1, 4];
const allPositive = arr.every(num => num > 0);
//Output: allPositive = false
8. 将文本复制到剪贴板
navigator.clipboard.writeText('Text to copy');
该代码使用了剪贴板API来实现自动复制文本到用户剪贴板的功能。这是一种现代的与剪贴板交互的方式,使得复制文本变得流畅且高效。
9. 创建一个唯一的数组
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(arr)];
// Output: unique = [1, 2, 3, 4, 5]
这里使用了 ` Set ` 对象,它存储唯一值,结合扩展运算符将其转换回数组。这是一种优雅的从数组中删除重复项的方法。
10. 找到两个数组的交集
const arr1 = [1, 2, 3, 4];
const arr2 = [2, 4, 6, 8];
const intersection = arr1.filter(value => arr2.includes(value));
// Output: intersection = [2, 4]
这个例子使用 ` Array.prototype.filter() ` 来查找 ` arr1 ` 和 ` arr2 ` 中的公共元素。回调函数检查是否每个 ` arr1 ` 元素都包含在 ` arr2 ` 中,从而生成一个包含交集值的数组。
11. 数组元素之和
const arr = [1, 2, 3, 4];
const sum = arr.reduce((total, value) => total + value, 0);
// Output: sum = 10
这个单行代码使用了 reduce 方法来将数组中所有值累积成一个总和。reduce 方法接受一个回调函数,该函数有两个参数:累加器( total )和当前值( value )。从初始值0开始,它遍历数组,将每个元素添加到总和中。
12. 条件对象属性
const condition = true;
const value = 'Hello World';
const newObject = {...(condition && {key: value})};
// Output: newObject = { key: 'Hello World' }
这种巧妙地运用扩展运算符( … )和短路求值的方法可以让你有条件地向一个对象添加一个属性。如果 condition 为真,则将 {key: value} 散列到该对象中;否则,不添加任何属性。
13. 动态对象键
const dynamicKey = 'name';
const value = 'John Doe';
const obj = {[dynamicKey]: value};
// Output: obj = { name: 'John Doe' }
这种语法称为计算属性名,它允许您使用变量作为对象键。在 dynamicKey 周围的方括号中,会运行其中的表达式并将其用作属性名。
14. 网络状态检查器
const isOnline = navigator.onLine ? 'Online' : 'Offline';
// Output: isOnline = 'Online' or 'Offline'
使用三元运算符,这段代码使用 ` navigator.onLine ` 检查浏览器的在线状态,如果为真则返回 “Online”,否则返回 “Offline”。这是一种快速检查用户连接状态的动态方法。也可以使用事件监听器来实现。
15. 确认后方可离开页面
window.onbeforeunload = () => 'Are you sure you want to leave?';
这段代码将钩入窗口的 onbeforeunload 事件,当用户试图离开页面时会触发确认对话框,有助于防止因未保存的更改而导致的数据丢失。
16. 以键值计算对象值的总和
const arrayOfObjects = [{x: 1}, {x: 2}, {x: 3}];
const sumBy = (arr, key) => arr.reduce((acc, obj) => acc + obj[key], 0);
sumBy(arrayOfObjects, 'x'));
// Output: 6
该函数使用 ` reduce ` 对数组中对象的特定键值进行求和运算。这是一种根据给定键值灵活计算数组中对象总值的方法。
17. 解析查询字符串为对象
const query = 'name=John&age=30';
const parseQuery = query => Object.fromEntries(new URLSearchParams(query));
// Output: parseQuery = { name: 'John', age: '30' }
这个表达式将查询字符串转换为一个对象。URLSearchParams 解析查询,而 Object.fromEntries 则将迭代对转换为一个对象,使得从URL参数中检索数据变得简单。
18. 将秒数转换为时间字符串
const seconds = 3661;
const toTimeString = seconds => new Date(seconds * 1000).toISOString().substr(11, 8);
toTimeString(seconds));
// Output: '01:01:01'
该语句将秒数转换为“HH:MM:SS”格式的字符串。它在UTC时间的起点(即1970年1月1日00:00:00)创建一个新的Date对象,然后将该对象转换为ISO格式字符串,并从中提取时间部分。
19. 对象的最大值
const scores = {math: 95, science: 99, english: 88};
const maxObjectValue = obj => Math.max(...Object.values(obj));
maxObjectValue(scores));
// Output: 99
这个单行代码会找出一个对象中数值的最大值。首先使用 Object.values(obj) 提取对象中的所有数值,并将其作为数组进行操作。然后,使用 Math.max 将数组展开,以找出其中的最大数值。
20.。检查对象是否包含值
const person = {name: 'John', age: 30};
const hasValue = (obj, value) => Object.values(obj).includes(value);
hasValue(person, 30);
// Output: true
该函数检查给定的值是否存在于某个对象的值中。首先,`Object.values` 获取该对象的值数组,然后 `includes` 检查给定的值是否在该数组中。
21. 条件性提升分数
const scores = [45, 75, 62, 55, 90];
const updatedScores = scores.map(score => score < 60 ? score + 20 : score);
// Output: updatedScores = [65, 75, 62, 75, 90]
这个一元表达式使用 Array.map() 方法遍历 scores 数组中的每个得分。在回调函数中使用了三元运算符( condition ? exprIfTrue : exprIfFalse )来检查一个得分是否低于60。如果是,则将得分增加20;否则,保持得分不变。这是一种在数组转换过程中应用条件逻辑的极好方式。对于根据条件逻辑调整数据而不需要冗长的 if-else 块来说再完美不过了。
22. 安全访问嵌套对象属性
const user = { profile: { name: 'John Doe' } };
const userName = user.profile?.name ?? 'Anonymous';
// Output: userName = 'John Doe'
这个一元表达式演示了如何使用可选链式操作符( ?. )安全地访问 name 中的 user.profile 。如果 user.profile 等于 undefined 或 null ,则会短路并返回 undefined ,从而避免了可能出现的 TypeError 。
空值合并运算符( ?? )然后检查左侧表达式的值是否为 null 或 undefined ,如果是,则默认为‘Anonymous’。这确保了在没有其他假值(如 ” 或 0 )触发的情况下,有一个默认的返回值。这对于在数据结构中访问嵌套较深的属性非常理想,因为某些中间属性可能不存在。
在 JavaScript 中,空值合并运算符( ?? )和逻辑或( || )都可以用来提供默认值,但它们在处理假值时的方式有所不同。
在上述示例中,将 ?? 更改为 || 会稍微改变行为。逻辑或( || )运算符如果左操作数为假,则返回右操作数。在 JavaScript 中,假值包括 null 、 undefined 、 0 、 NaN 、 ” (空字符串)和 false 。这意味着 || 运算符将返回任何这些假值的右操作数,而不仅仅是 null 或 undefined 。
23. 条件执行
const isEligible = true;
isEligible && performAction();
// performAction is called if isEligible is true
利用逻辑与(&)运算符(&),该模式仅在 isEligible 的值为 true 时执行 performAction() 。这是一种简洁的方式来在不使用 if 语句的情况下条件执行函数。这在根据条件执行函数时可能很有用,尤其是在事件处理程序或回调函数中。
24. 生成一系列数字
const range = Array.from({ length: 5 }, (_, i) => i + 1);
// Output: range = [1, 2, 3, 4, 5]
它创建一个来自数组对象或迭代对象的新数组。在这里,它使用了一个具有 length 属性和映射函数的对象。映射函数( (_, i) => i + 1 )使用索引( i )生成从1到5的数字。下划线( _ )是一个约定,表示该参数未被使用。
25. 实现带超时的 Promise
const timeout = (promise, ms) => Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), ms))
]);
timeout(fetch('https://api.example.com'), 5000).then(handleResponse).catch(handleError);
这段代码创建了一个承诺,如果在指定的毫秒数内未被解决,则会抛出一个“Timeout”错误。它使用 Promise.race() 来让提供的 promise 与一个自动在 ms 毫秒后拒绝的超时承诺进行比赛。这对于为 fetch 请求或任何可能挂起或运行时间过长的异步操作添加超时行为非常有用。
如果你以前从未在 JavaScript 中使用过 Promises 的话,那么上面的内容可能需要更多的解释。
在 JavaScript 中,Promise 表示异步操作最终完成(或失败)及其产生的值。Promise 可以处于以下这些状态之一:“pending”(等待中):表示操作尚未完成,但即将完成。“fulfilled”(完成):表示操作已成功完成,并已返回一个值。“rejected”(拒绝):表示操作已失败,并已返回一个错误值。
- 待定状态:承诺的初始状态。操作尚未完成。
- 完成:操作成功完成,Promise 具有值。
- 拒绝:操作失败,Promise 包含失败原因。
Promise可以让您将回调函数附加到处理完成值或拒绝原因的操作上,而不必直接处理操作的异步特性。
使用 Promise.race()
`Promise.race()` 方法接受一个可迭代的 Promise 对象数组,并返回一个新的 Promise,该 Promise 会在数组中任何一个 Promise 完成或拒绝时也随之完成或拒绝,并使用来自该 Promise 的值或错误信息。
“ timeout ”函数是如何工作的?
示例中提供的 `timeout` 函数将任何 Promise(本例中为一个 `fetch` 请求)封装了超时功能。它在提供的 Promise 和一个在指定超时时间(以毫秒计)后自动拒绝的新 Promise 之间创建了一个竞争条件。
这种方法特别有用,它可以确保您的应用程序能够优雅地处理异步操作可能出现的挂起或耗时过长的情况,通过提供一种机制来“放弃”并将超时作为错误处理。
26. 提取文件扩展名
const fileName = 'example.png';
const getFileExtension = str => str.slice(((str.lastIndexOf(".") - 1) >>> 0) + 2);
// Output: getFileExtension = 'png'
这个表达式从字符串中提取文件扩展名。它查找最后一个点字符( . )的位置,并从该位置开始到字符串末尾截取字符串。位运算符( >>> )确保即使找不到点字符,操作也能安全完成,从而在找不到点字符的情况下有效返回空字符串。
27. 检查当前标签页是否处于激活状态
const isTabFocused = () => document.hasFocus();
// Output: true (if the tab is focused), false otherwise
使用` document.hasFocus() ` 方法检查文档(或标签)是否获得焦点。这是一种直接的方法,可以确定用户是否正在积极查看或与页面进行交互。可以根据用户是否在场来暂停或恢复活动,例如在用户切换标签时停止视频播放。
28. 元素上的类名切换
const element = document.querySelector('.my-element');
const toggleClass = (el, className) => el.classList.toggle(className);
toggleClass(element, 'active');
该函数使用 ` classList.toggle() ` 方法向元素的类列表中添加或删除一个类。如果该类已经存在,则将其删除;如果不存在,则将其添加。这是一种处理基于用户交互或应用程序状态的动态类更改的优雅方式。非常适合实现根据用户操作或应用程序状态显示或隐藏的响应式设计元素,例如菜单或模态框。
就是这样!
上面是28个JavaScript单行代码,它们能够以简洁高效的方式实现强大的功能。
你还知道哪些类似的技巧,欢迎留言交流。
原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/79520.html