概要
本文介绍了 28 个 JavaScript 的一行代码,为常见的编程任务提供了实用且高效的解决方案。每个一行代码都有简要的解释和示例,展示了其用法。
1. 不使用临时变量交换值
let a = 1, b = 2
[a, b] = [b, a]
const array = [1, 2, 3, 4]
[a[1], a[2]] = [a[2], a[1]];
这个单行代码使用数组解构来交换 a 和 b 的值,而无需使用临时变量。[a, b] = [b, a] 这种语法通过解构右侧的数组并将其赋值给左侧变量来交换它们的值。
相当于这样:
let a = 1, b = 2
const c = [b, a]
[a, b] = c
2. 对象解构用于简化数据访问
const {name, age} = {name: 'John', age: 30};
// Output: name = 'John', age = 30
这里,对象解构用于直接从对象中提取名称和年龄属性到变量中。这种方法简化了对对象属性的访问,并提高了代码的可读性。
3. 快速克隆对象
const originalObj = {name: 'Jane', age: 22};
const clonedObj = {...originalObj};
// Output: clonedObj = {name: 'Jane', age: 22}
展开操作符(…)被用来创建originalObj的浅克隆。这会将原始对象中的所有可枚举的自有属性复制到一个新对象中。
如果属性值是一个对象的话,则 clonedObj 中属性的值指向 originalObj 中相同属性的值。
const originalObj = { jane: { name: 'Jane', age: 22 } };
const clonedObj = { ...originalObj };
// Output: clonedObj = {jane: {name: 'Jane', age: 22}}
clonedObj.jane.age = 23;
// Output:
// clonedObj = { jane: { name: 'Jane', age: 23 } }
// originalObj = { jane: { name: 'Jane', age: 23 } }
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]
这个巧妙的方法使用 Array.prototype.filter() 方法,并且将 Boolean 构造函数作为回调函数。它会从数组中移除所有的假值(0, false, null, undefined, ‘’, NaN)。
6、将 NodeList 转换为数组
const nodesArray = [...document.querySelectorAll('div')];
展开操作符用于将 NodeList(由 document.querySelectorAll 返回)转换为 JavaScript 数组,从而可以使用 map、filter 等数组方法。
7、检查数组是否满足特定条件
const arr = [1, 2, 3, -1, 4];
const hasNegativeNumbers = arr.some(num => num < 0);
// Output: hasNegativeNumbers = true
.some() 方法检查数组中是否有至少一个元素通过了提供的函数实现的测试(这里是指是否为负数),
而 .every() 则检查是否所有元素都通过了测试(是否为正数)。
const arr = [1, 2, 3, -1, 4];
const allPositive = arr.every(num => num > 0);
//Output: allPositive = false
8、复制文字到剪切板
navigator.clipboard.writeText('Text to copy');
这行代码使用 Clipboard 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 中的共同元素。回调函数检查 arr2 是否包含 arr1 的每个元素,结果是一个包含交集值的数组。
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?';
这行代码监听 window 的 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));
// 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 格式的时间字符串。它创建一个在给定秒数之后的纪元的新 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(obj) 获取对象值的数组,而 includes(value) 检查该值是否在该数组中。
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'
这个单行代码展示了使用可选链操作符 (?.) 安全地访问 user.profile 中的 name 属性。如果 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
利用逻辑 AND (&&) 操作符,这种模式仅在 isEligible 计算结果为 true 时执行 performAction()。这是一种无需 if 语句即可有条件地执行函数的简洁方式。这在基于条件执行函数时特别有用,尤其是在事件处理程序或回调中。
24、 生成一个数字范围
const range = Array.from({ length: 5 }, (_, i) => i + 1);
// Output: range = [1, 2, 3, 4, 5]
Array.from() 从一个类数组或可迭代对象创建一个新数组。在这里,它接受一个具有 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);
这段代码创建了一个promise,如果在指定的时间内没有得到解决,它会因为“超时”错误而拒绝。它使用 Promise.race() 来让给定的承诺与一个超时promise竞争,该超时承诺在毫秒数后自动拒绝。这对于给 fetch 请求或任何可能挂起或耗时过长的异步操作添加超时行为非常完美。
如果你之前没有使用过 JavaScript 中的 Promise,那么上面的内容可能需要更多的解释。JavaScript 中的 Promise 代表一个异步操作最终完成(或失败)及其结果值。一个 Promise 可以处于以下这些状态之一:
- 待定(Pending):Promise 的初始状态。操作还没有完成。
- 已兑现(Fulfilled):操作成功完成,Promise 有一个值。
- 已拒绝(Rejected):操作失败,Promise 有一个失败的原因。
Promise 允许你附加回调来处理已兑现的值或拒绝的原因,
使用 Promise.race()
Promise.race() 方法接受一个 Promise 对象的可迭代对象,并返回一个新的 Promise,该 Promise 会在可迭代对象中的任意一个 Promise 解决或拒绝后立即解决或拒绝,并带有该 Promise 的值或原因。
超时函数如何工作
示例中提供的 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()方法可以检查文档(或标签页)是否具有焦点。这是一种直接的方式来确定用户是否正在积极查看或与页面互动。可以根据用户的存在来使用它暂停或恢复活动,例如,当用户切换标签页时停止视频播放。以下是一个简单的示例,说明如何使用document.hasFocus()来控制视频播放:
var video = document.querySelector('video');
window.addEventListener('blur', function() {
if (document.hasFocus()) {
// Do nothing if the blur event was triggered by a modal or something within the page
} else {
// Pause the video if the user switches tabs or moves focus away from the browser window
video.pause();
}
});
window.addEventListener('focus', function() {
// Resume the video if the user returns to the tab or focuses on the browser window
if (document.hasFocus()) {
video.play();
}
});
28、切换元素类名
const element = document.querySelector('.my-element');
const toggleClass = (el, className) => el.classList.toggle(className);
toggleClass(element, 'active');
这个函数使用了classList.toggle()方法来从一个元素的类列表中添加或移除一个类。如果该类已存在,则将其移除;如果不存在,则将其添加。这是一种处理基于用户交互或应用程序状态动态类变化的好方法。它非常适合实现响应式设计元素,比如基于用户行为显示或隐藏的菜单或模态框。
以上~! 原文地址:# 28 JavaScript One-Liners every Senior Developer Needs to Know