在前端编程中,高质量的代码不仅实现功能,还注重可读性、可维护性和性能。以下是一些值得品味和学习的优质前端代码片段,涵盖了函数式编程、ES6新特性、以及一些最佳实践示例:
文章目录
- 1. 箭头函数与数组方法结合使用
- 2. 解构赋值
- 3. 模板字符串
- 4. 使用Set去重
- 5. Promise链式调用
- 6. 立即执行函数表达式(IIFE)用于模块化
- 7. 使用默认参数和Rest参数
- 8.时间函数 - 格式化日期
- 9.文件上传 - 预览图片
- 10.单行与多行文本省略
- 11.动画效果 - 使用requestAnimationFrame实现平滑滚动
- 12.DOM操作 - 动态创建与插入元素
- 13.异步- async/await处理异步操作
- 14.ES6解构与展开运算符 - 快速交换变量值
- 15.Promise.allSettled 与并发请求管理
- 16.使用 async/await 和 try/catch 进行错误处理
- 17.生成器函数与迭代协议
- 18.使用Map和Set进行高效数据操作
- 19.防抖(debounce)函数 - 减少高频触发的函数调用
- 20.限制并发
- 21.解构赋值与默认值结合
- 22.扁平化数组与映射
- 23.使用Proxy进行对象属性访问的监控
- 24.利用Symbol实现私有属性
- 25.利用async iterators处理异步流
- 26.使用CSS Custom Properties(变量)进行主题切换
1. 箭头函数与数组方法结合使用
const numbers = [1, 2, 3, 4, 5];
const squared = numbers.map(number => number * number);
console.log(squared); // 输出: [1, 4, 9, 16, 25]
这段代码展示了如何使用箭头函数和map方法简洁地对数组元素进行操作。
2. 解构赋值
const user = { firstName: 'John', lastName: 'Doe' };
const { firstName, lastName } = user;
console.log(`${firstName} ${lastName}`); // 输出: John Doe
解构赋值使得从对象或数组中提取值变得非常直观和简洁。
3. 模板字符串
const name = 'Alice';
const greeting = `Hello, ${name}! Welcome to our website.`;
console.log(greeting); // 输出: Hello, Alice! Welcome to our website.
模板字符串提供了一种更自然的方式来插入变量和表达式到字符串中,增强了代码的可读性。
4. 使用Set去重
const array = [1, 2, 2, 3, 4, 4, 5];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // 输出: [1, 2, 3, 4, 5]
利用Set
数据结构的唯一性,可以优雅地去除数组中的重复元素。
5. Promise链式调用
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
展示了如何使用Promise
来处理异步操作,保持代码结构清晰,易于理解和维护。
6. 立即执行函数表达式(IIFE)用于模块化
(function() {
const privateVar = 'I am private';
window.myModule = {
publicMethod: function() {
console.log(privateVar);
}
};
})();
myModule.publicMethod(); // 输出: I am private
IIFE用来创建作用域,避免全局污染,是早期JavaScript
中实现模块化的一种方式。
7. 使用默认参数和Rest参数
function greet(name = 'Guest', ...greetings) {
greetings.forEach(greeting => console.log(`${greeting}, ${name}!`));
}
greet('Alice', 'Hello', 'Welcome');
// 输出:
// Hello, Alice!
// Welcome, Alice!
默认参数使得函数调用更加灵活,而Rest
参数允许你将不确定数量的参数作为一个数组传入。
8.时间函数 - 格式化日期
function formatDate(date) {
const options = { year: 'numeric', month: 'long', day: 'numeric' };
return new Date(date).toLocaleDateString('zh-CN', options);
}
console.log(formatDate(new Date())); // 输出:如 "2023年4月16日"
9.文件上传 - 预览图片
<input type="file" id="imageFile" accept="image/*" />
<img id="preview" src="#" alt="Image preview" style="display:none;" />
<script>
document.getElementById('imageFile').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
document.getElementById('preview').src = event.target.result;
document.getElementById('preview').style.display = 'block';
};
reader.readAsDataURL(file);
}
});
</script>
10.单行与多行文本省略
单行与多行文本省略
<p class="single-line-ellipsis">这是一个很长很长的句子,可能会超出容器的宽度。</p>
.single-line-ellipsis {
width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
多行文本省略
<p class="multi-line-ellipsis">这里是一个多行文本的例子,它将会在超过指定行数后被省略显示,以保持界面的整洁。</p>
.multi-line-ellipsis {
display: -webkit-box;
-webkit-line-clamp: 3; /* 显示行数 */
-webkit-box-orient: vertical;
overflow: hidden;
}
11.动画效果 - 使用requestAnimationFrame实现平滑滚动
function smoothScroll(target, duration) {
const start = window.pageYOffset;
const distance = target.getBoundingClientRect().top;
const startTime = performance.now();
function step(currentTime) {
const timeElapsed = currentTime - startTime;
const progress = Math.min(timeElapsed / duration, 1);
window.scrollTo(0, start + distance * progress);
if (timeElapsed < duration) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}
// 使用方法:平滑滚动到页面顶部
smoothScroll(document.documentElement, 1000);
12.DOM操作 - 动态创建与插入元素
function createElementWithText(tag, text) {
const element = document.createElement(tag);
element.textContent = text;
return element;
}
const div = createElementWithText('div', '新创建的Div元素');
document.body.appendChild(div);
13.异步- async/await处理异步操作
async function fetchUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const userData = await response.json();
console.log(userData);
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}
fetchUserData(123);
14.ES6解构与展开运算符 - 快速交换变量值
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 输出: 2 1
15.Promise.allSettled 与并发请求管理
使用 Promise.allSettled
处理多个异步操作,无论这些操作成功还是失败,都能获取到每个操作的结果。
async function fetchResources(urls) {
const promises = urls.map(url =>
fetch(url).then(response => ({
status: 'fulfilled',
value: response
})).catch(error => ({
status: 'rejected',
reason: error
}))
);
return Promise.allSettled(promises);
}
const urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
fetchResources(urls).then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Resource ${index + 1} fetched successfully.`);
} else {
console.error(`Failed to fetch resource ${index + 1}:`, result.reason);
}
});
});
16.使用 async/await 和 try/catch 进行错误处理
优雅地处理异步操作中的错误,提高代码可读性。
async function fetchData(id) {
try {
const response = await fetch(`https://api.example.com/items/${id}`);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log(data);
} catch(error) {
console.error('There was a problem fetching the data:', error);
}
}
fetchData(123)
17.生成器函数与迭代协议
function* fibonacci() {
let prev = 0, curr = 1;
while (true) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
const fibGen = fibonacci();
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 2
18.使用Map和Set进行高效数据操作
利用ES6
的Map
和Set
数据结构来解决特定问题,提高代码效率。
const map = new Map();
map.set('apple', 1);
map.set('banana', 2);
console.log(map.get('apple')); // 输出: 1
const set = new Set([1, 2, 3, 9, 5, 2]);
console.log([...new Set([...set].filter(x => x % 2 === 0))]); // 输出去重后的偶数集合: [2, 4]
19.防抖(debounce)函数 - 减少高频触发的函数调用
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
const handleResize = debounce(function() {
console.log('窗口大小已调整');
}, 300);
window.addEventListener('resize', handleResize);
20.限制并发
/**
* 异步并发控制函数
*
* @param {number} poolLimit - 并发执行的最大任务数量
* @param {Iterable<any>} iterable - 包含待执行任务输入的可迭代对象
* @param {(item: any, index: number) => Promise<any>} iteratorFn - 异步任务处理器,接收迭代对象的元素和其索引为参数
* @returns {Promise<any[]>} - 所有异步任务完成后的结果数组
*/
async function asyncPool(poolLimit, iterable, iteratorFn) {
// 结果数组,用于收集所有异步任务的完成结果
const results = [];
// 正在执行的任务集合,使用Set以便快速查找和删除
const executing = new Set();
// 遍历可迭代对象
for (const [index, item] of iterable.entries()) {
// 构建异步任务Promise,并立即执行
const taskPromise = (async () => {
try {
// 执行异步任务并等待结果
const result = await iteratorFn(item, index);
results[index] = result; // 根据索引位置填充结果数组
} finally {
// 无论任务成功还是失败,都要从执行集合中移除
executing.delete(taskPromise);
}
})();
// 添加到执行集合
executing.add(taskPromise);
// 控制并发数量,当达到限制时等待任何一个任务完成
if (executing.size >= poolLimit) {
await Promise.race(executing);
}
}
// 确保所有任务(即使在循环结束时尚未启动的)都完成
await Promise.all(executing);
return results;
}
// 示例使用
(async () => {
// 模拟异步任务函数,参数i模拟不同的延迟时间
const delayAsync = (i) => new Promise(resolve => setTimeout(() => resolve(`Task ${i} done after ${i}ms`), i));
// 调用asyncPool控制并发执行
const results = await asyncPool(2, [1000, 2000, 500, 1500], delayAsync);
console.log(results);
})();
21.解构赋值与默认值结合
function welcomeUser({ name = 'Guest', role = 'Visitor' }) {
console.log(`Welcome, ${name} (${role})!`);
}
welcomeUser({ name: 'Alice' }); // 输出: Welcome, Alice (Visitor)!
welcomeUser({}); // 输出: Welcome, Guest (Visitor)!
22.扁平化数组与映射
const nestedArray = [[1, 2], [3, 4], [5]];
const flatMappedArray = nestedArray.flat().map(item => item * 2);
console.log(flatMappedArray); // 输出: [2, 4, 6, 8, 10]
23.使用Proxy进行对象属性访问的监控
const person = { name: 'Alice', age: 30 };
const personProxy = new Proxy(person, {
get(target, prop) {
console.log(`Accessing property: ${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`Setting property ${prop} to ${value}`);
target[prop] = value;
return true;
}
});
personProxy.name; // 输出: Accessing property: name
personProxy.age = 31; // 输出: Setting property age to 31
24.利用Symbol实现私有属性
const _secret = Symbol('secret');
class SecretHolder {
constructor(secret) {
this[_secret] = secret;
}
revealSecret() {
return this[_secret];
}
}
const instance = new SecretHolder('classified information');
console.log(instance.revealSecret()); // 输出: classified information
// 注意:直接访问_secret属性是不可见的,保护了私有性
25.利用async iterators处理异步流
async function* generateNumbers(limit) {
for (let i = 1; i <= limit; i++) {
await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟异步
yield i;
}
}
(async () => {
for await (const num of generateNumbers(5)) {
console.log(num);
}
})();
// 每秒输出一个数字,从1到5
26.使用CSS Custom Properties(变量)进行主题切换
CSS变量不仅简化了样式管理,还便于实现动态主题切换功能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Theme Switcher</title>
<style>
:root {
--primary-color: #3f51b5;
--secondary-color: #f50057;
--text-color: #ffffff;
}
body {
color: var(--text-color);
background: var(--primary-color);
}
.button {
background-color: var(--secondary-color);
color: var(--text-color);
border-radius: 4px;
padding: 10px 20px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: darken(var(--secondary-color), 10%);
}
/* 假设有一个按钮用于切换主题 */
.toggle-button {
cursor: pointer;
}
/* 主题切换示例 */
.dark-theme {
--primary-color: #212121;
--secondary-color: #9c27b0;
}
</style>
</head>
<body>
<button class="button toggle-button">Toggle Dark Theme</button>
<script>
// 这里需要JavaScript来实际切换主题类
document.querySelector('.toggle-button').addEventListener('click', function() {
document.body.classList.toggle('dark-theme');
});
</script>
</body>
</html>