9 個簡潔的 JavaScript 一行代碼技巧,幫你取代 50 行代碼
我们都在某个时候看过一些可怕的JavaScript代码段落,在心里暗自咒骂,心里明白一定有更好的解决方法。
学了一段时间之后,我发现了一些简洁的单行代码,这些单行代码可以替代许多冗长的代码。这些代码真是太棒了。
这些确实是利用现代JavaScript特性解决常见问题的方法,非常实用且容易阅读的技巧。
所以,无论是清理代码还是开始新项目,这些技巧都能帮助你写出更优雅且容易维护的代码。
这里有9个超实用的一句话妙招,你今天就可以用起来。
展平嵌套数组在过去,你是否曾经尝试过展平一个嵌套很深的数组?这通常需要多层循环、临时数组,以及过多的代码。
但现在它被精彩地执行在一个强大的单行代码里。
const 平铺数组 = arr => arr.flat(Infinity); // 将数组展平
const 嵌套数组 = [1, [2, 3, [4, 5, [6, 7]]], 8, [9, 10]]; // 包含多个层级的嵌套数组
const 展平后的数组 = 平铺数组(嵌套数组);
// 结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 展平后的数组
请选择: 点击进入全屏, 点击退出全屏.
要是用传统的方法来做这件事,你可能会得到这样的结果。
function 深度展平数组艰难方式(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
// 判断是否为数组
result = result.concat(深度展平数组艰难方式(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
}
// 此函数将以困难的方式展平嵌套数组,这意味着如果数组元素自身还是数组,它会递归地展平这些元素
进入全屏。退出全屏。
所有的繁重任务都交给 flat() 来处理,而添加 Infinity 则让它可以向下遍历任意深度。简单、干净,而且管用。
对象深克隆:不依赖其他对象的深度克隆如果你需要真正的深层克隆对象,并且不希望引入lodash,这里有一个无需依赖的解决方案,它可以处理嵌套对象、数组以及日期。
const deepClone = obj => JSON.parse(JSON.stringify(obj));
const 用户对象 = {
user: { name: 'Alex', date: new Date() },
scores: [1, 2, [3, 4]],
active: true
};
const 克隆 = deepClone(用户对象);
切换到全屏模式,退出全屏模式
老方法?得像这样输入:
function manualDeepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
const clone = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clone[key] = manualDeepClone(obj[key]);
}
}
return clone;
}
全屏模式退出全屏
小提示: 这条简短的代码片段有一些限制——它不能处理函数、符号或循环引用。但对于90%的情况来说,它还是很实用的。
将 CSV 转换为对象列表这是一个不错的代码行,它将CSV数据转换为可供操作的对象数组,非常适合于API的响应或读入数据。
const csvToObjects = csv => csv.split('\n').map(row => Object.fromEntries(row.split(',').map((value, i, arr) => [arr[0].split(',')[i], value])));
const csvData = `名字,年纪,所在城市
Peboy,30,纽约市
Peace,25,旧金山市
Lara,35,芝加哥市`;
const parsed = csvToObjects(csvData);
// 结果如下:
// [
// { 名字: 'Peboy', 年纪: '30', 所在城市: '纽约市' },
// { 名字: 'Peace', 年纪: '25', 所在城市: '旧金山市' },
// { 名字: 'Lara', 年纪: '35', 所在城市: '芝加哥市' }
// ]
全屏模式 退出全屏
嗯,你可能会写这样的东西吧。
/**
* 将CSV转换为对象
* @param {string} csv - CSV字符串
* @returns {object[]} 转换后的对象数组
*/
function 将CSV转换为对象(csv) {
const 行 = csv.split('\n');
const 标题 = 行[0].split(',');
const 结果 = [];
for (let i = 1; i < 行.length; i++) {
const 对象 = {};
const 当前行 = 行[i].split(',');
for (let j = 0; j < 标题.length; j++) {
对象[标题[j]] = 当前行[j];
}
结果.push(对象);
}
return 结果;
}
点击这里全屏 点击这里退出全屏
这是一种用一行代码有效进行数据转换的方法,但在投入使用之前,最好先增加一些错误处理机制。
数组操作:去重和排序这里有一条简化的代码行,可以同时删除重复项并排序数组,非常适合清理数据。
const uniqueSorted = arr => [...new Set(arr)].sort((a, b) => a - b);
// 例如它的用法:
const messyArray = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
const cleaned = uniqueSorted(messyArray);
// 结果如下:[1, 2, 3, 4, 5, 6, 9]
// 对于字符串的排序
const messyStrings = ['banana', 'apple', 'apple', 'cherry', 'banana'];
const cleanedStrings = [...new Set(messyStrings)].sort();
// 结果如下:['apple', 'banana', 'cherry']
打开全屏 关闭全屏
这就是以前的样子:
function 手动清理数组(arr) {
const unique = [];
for (let i = 0; i < arr.length; i++) {
if (unique.indexOf(arr[i]) === -1) {
unique.push(arr[i]);
}
}
return unique.sort((a, b) => a - b);
}
全屏,退出
Set 能完美去重,然后通过展开运算符将它再转为数组。最后,只需调用 sort() 方法即可排序!
DOM 操纵:查找和修改多个节点这里有一句非常强大的代码,可以让你同时查询和转换多个DOM元素。
const modifyElements = selector => Array.from(document.querySelectorAll(selector)).forEach(el => el.style);
// 可以这样用:
const updateButtons = modifyElements('.btn')
.map(style => Object.assign(style, {
backgroundColor: '#007bff',
color: 'white',
padding: '10px 20px'
}));
// 调整按钮样式
// 或者更简单地切换按钮状态:
const toggleAll = selector => document.querySelectorAll(selector).forEach(el => el.classList.toggle('active'));
全屏, 退出全屏
按传统,
function updateElementsManually(selector) {
// 更新元素的背景色和文字颜色等样式
const elements = document.querySelectorAll(selector);
for (let i = 0; i < elements.length; i++) {
const el = elements[i];
// 设置元素的背景色为 #007bff
el.style.backgroundColor = '#007bff';
// 设置元素的文字颜色为白色
el.style.color = 'white';
// 设置元素的内边距为 10px 20px
el.style.padding = '10px 20px';
}
}
进入全屏 恢复窗口
这在所有现代浏览器中都可以运行,从而避免编写重复的DOM操作。
并行 API 调用及其清晰的错误处理这是一行简洁的代码,可以并行调用APIs,同时错误处理得非常干净。
const parallelCalls = urls => Promise.allSettled(urls.map(url => fetch(url).then(r => r.json())));
// 把它用起来:
const urls = [
'https://api.example.com/users',
'https://api.example.com/posts',
'https://api.example.com/comments'
];
// 一行代码搞定:
const getData = async () => {
const results = await parallelCalls(urls);
// 解析结果,提取已成功加载的数据
const [users, posts, comments] = results.map(r => r.status === 'fulfilled' ? r.value : null);
};
切换到全屏模式。退出全屏。
换句话说,如果要说得更详细一点:
async function fetchDataManually(urls) {
// 这个函数是用来手动获取数据的。
const results = [];
for (const url of urls) {
try {
const response = await fetch(url);
const data = await response.json();
results.push({ status: 'fulfilled', value: data });
} catch (error) {
results.push({ status: 'rejected', reason: error });
}
}
return results;
}
按一下全屏 开启或关闭
Promise.allSettled
是这里的英雄;即使一个请求失败了,它也不会导致整体失败,并且为每个请求提供明确的状态结果。
这里有一句甜蜜的妙语,可以将日期转换为干净整洁的字符串,而且无需任何外部依赖。
const formatDate = date => new Intl.DateTimeFormat('zh-CN', { dateStyle: 'long', timeStyle: 'short' }).format(date);
const now = new Date();
console.log(formatDate(now));
// 输出: '2024年12月5日星期四 下午2:30'
// 想要不同格式?很简单:
const shortDate = date => new Intl.DateTimeFormat('zh-CN', { month: 'short', day: '2-digit', year: 'numeric' }).format(date);
// 输出: '2024年12月5日'
切换到全屏模式,退出全屏
老式的方法是这样的。
function formatDateManually(date) {
const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const 月份 = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
const dayName = days[date.getDay()];
const monthName = 月份[date.getMonth()];
const day = date.getDate();
const year = date.getFullYear();
const hours = date.getHours();
const minutes = date.getMinutes();
const ampm = hours >= 12 ? '下午' : '上午';
return `${year}年${monthName}${day}, 星期${dayName} ${hours % 12}: ${minutes.toString().padStart(2, '0')} ${ampm}时`;
}
进入全屏 退出全屏
Intl.DateTimeFormat
(注:一种处理日期格式的国际标准方法)负责处理所有的复杂任务,包括本地化。再也不用手动拼接日期字符串了!
这里有一个简洁的一行代码,可以为任何函数创建一个防抖函数——非常适用于搜索框输入或窗口大小调整事件处理程序:
const debounce=(fn,ms)=>{let timeout;return(...args)=>{clearTimeout(timeout);timeout=setTimeout(()=>fn(...args),ms);};};
// 试试这个用法:
const expensiveSearch=query=>console.log('搜索查询:',query);
const debouncedSearch=debounce(expensiveSearch,300);
// 在输入事件监听器中使用它:
searchInput.addEventListener('input',e=>debouncedSearch(e.target.value));
进入全屏,退出全屏
传统的方式如下:
function 创建防抖函数(fn, delay) {
let 超时ID;
return function 防抖(...args) {
if (超时ID) {
clearTimeout(超时ID);
}
超时ID = setTimeout(() => {
fn.apply(this, args);
超时ID = null;
}, delay);
};
}
切换到全屏模式: 退出全屏
这一行代码可以处理所有基本的防抖用例,并且避免不必要的函数调用,尤其是在快速连续输入,如打字或调整窗口大小时。
本地对象存储:具有验证功能的对象存储这里有一个简洁的代码行,用于在 localStorage 中存储对象,并自带验证和错误处理。
const store = key => ({ get: () => JSON.parse(localStorage.getItem(key)), set: data => localStorage.setItem(key, JSON.stringify(data)), remove: () => localStorage.removeItem(key) });
// 用法如下:
const userStore = store('user');
// 存数据
userStore.set({ id: 1, name: 'John', preferences: { theme: 'dark' } });
// 取数据
const userData = userStore.get();
// 删数据
userStore.remove();
全屏模式 全屏退出
老方法可能这样:
function handleLocalStorage(key) {
return {
get: function() {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
} catch (e) {
console.error('读取localStorage数据时出错:', e);
return null;
}
},
set: function(data) {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error('写入localStorage数据时出错:', e);
}
},
remove: function() {
try {
localStorage.removeItem(key);
} catch (e) {
console.error('移除localStorage数据时出错:', e);
}
}
};
}
点击此处切换到全屏模式,点击此处切换回正常模式
这个库为你提供了简洁易用的localStorage操作接口,并自动处理JSON数据的解析与序列化,无需手动处理。
结尾这些一行代码技巧不仅仅是为了减少代码——更是为了写出更聪明的代码。每一个技巧都以一种清晰、可维护的方式解决了常见的 JavaScript 难题。虽然这些代码片段确实非常强大,但请记住,可读性永远是第一位的。如果一行代码让代码更难理解,那就拆分成多行。
在你的项目中可以随意混合使用这些模式,并且别忘了检查浏览器的兼容性,尤其是当你需要支持旧版浏览器时,特别是查看新特性,比如 flat()
或 Intl.DateTimeFormat
的兼容性。
有你自己强大的JavaScript一行代码吗?我很想看看哦!
关注我[X]上的更多JavaScript技巧、窍门和 web 开发讨论,让我们的开发生活更轻松。我经常分享一些实用的代码片段和最佳实践。
保持好奇,不断编码,并记住:好的代码不在于写的少,而在于能否清晰地表达你的意图。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章