JavaScript实战案例
1. 工具函数
1.1 如何判断一个对象是不是空对象
可以使用以下几种判断对象是否为空的方法。
Object.keys()
在使用这个方法之前,我们需要对传入的对象进行判空,Object.keys() 返回一个包含对象所有可枚举属性的数组。如果这个数组的长度为 0,那么对象就是空的。
javascriptfunction isEmptyObject(obj) { return obj && typeof obj === 'object' && Object.keys(obj).length === 0; } let emptyObj = {}; console.log(isEmptyObject(emptyObj)); // true let nonEmptyObj = { key: 'value' }; console.log(isEmptyObject(nonEmptyObj)); // false
for...in 循环
如果你需要兼容较老的浏览器,可以使用 for...in 循环。这个方法会遍历对象的所有可枚举属性。如果找到任何一个属性,就说明对象不为空。
javascriptfunction isEmptyObject(obj) { for (let prop in obj) { if (Object.hasOwn(obj, prop)) { return false; } } return true; }
JSON.stringify()
这个方法将对象转换为 JSON 字符串,然后比较是否等于 '{}'。不过要注意,这个方法可能会有一些边界情况,比如对象中包含 undefined、函数等值时可能会出现问题。
javascriptfunction isEmptyObject(obj) { return JSON.stringify(obj) === '{}'; }
Object.getOwnPropertyNames()
这个方法比 Object.keys() 更严格,因为它会检查所有属性,而不仅仅是可枚举属性。
javascriptfunction isEmptyObject(obj) { return Object.getOwnPropertyNames(obj).length === 0; }
1.2 如何判断网页元素是否到达可视区域
判断网页元素是否到达可视区域是一个常见的需求,尤其在实现懒加载、无限滚动或者触发动画等场景中非常有用。有以下几种几种:
Intersection Observer API
这是我最推荐的方法,因为它既高效又简单。Intersection Observer API 可以异步地观察目标元素与其祖先元素或视口的交叉状态。
javascriptconst observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { console.log('元素进入可视区域'); // 在这里执行你的逻辑 } }); }); const target = document.querySelector('#your-element'); observer.observe(target);
这种方法的优点是性能好,不会阻塞主线程,而且使用起来相对简单。
getBoundingClientRect() 方法
如果需要更精确的控制或者需要兼容旧版浏览器,我们可以使用 getBoundingClientRect() 方法。这个方法返回元素的大小及其相对于视口的位置。
javascriptfunction isElementInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } // 使用 const element = document.querySelector('#your-element'); if (isElementInViewport(element)) { console.log('元素在可视区域内'); }
这种方法的优点是可以精确控制元素的可见范围,但需要注意的是,如果在滚动事件中频繁调用,可能会影响性能。
在使用 getBoundingClientRect() 方法时,可以使用节流(throttle)或防抖(debounce)技术来限制函数的调用频率,以避免过度消耗性能。
Element.checkVisibility() 方法
这是一个相对较新的 API,可以直接检查元素是否可见:
javascriptconst element = document.querySelector('#your-element'); if (element.checkVisibility()) { console.log('元素可见'); }
这个方法还可以接受一个选项对象,用于进行更细粒度的检查。
javascriptelement.checkVisibility({ checkOpacity: true, // 检查 opacity 是否为 0 checkVisibilityCSS: true // 检查 visibility CSS 属性 });
虽然这个方法使用起来很简单,但需要注意浏览器兼容性问题 实际开发中。
如果是现代浏览器环境,我会优先选择 Intersection Observer API,因为它既高效又易用。如果需要更精确的控制或者需要兼容旧版浏览器,我会使用 getBoundingClientRect() 方法。
2. 原理学习
2.1 使用 async
/await
模拟阻塞
虽然 JavaScript 本身不支持真正的阻塞操作,但我们可以使用 async
/await
和 Promise
来模拟阻塞行为。例如,我们可以创建一个 Promise
,该 Promise
在满足某个条件之前不会解决,从而模拟阻塞。
以下是一个简单的例子,其中 sleep
函数模拟了一个阻塞操作:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function blockingOperation() {
console.log('Starting blocking operation...');
await sleep(2000); // 模拟阻塞 2 秒
console.log('Blocking operation completed.');
}
blockingOperation();
在这个例子中,sleep
函数返回一个在指定毫秒数后解决的 Promise
。blockingOperation
函数使用 await
关键字等待 sleep
函数完成,从而模拟了阻塞行为。
// 定义一个返回 Promise 的函数,模拟异步操作(如网络请求)
function fetchData() {
return new Promise((resolve) => {
// 使用 setTimeout 模拟网络延迟
setTimeout(() => {
resolve("数据已获取");
}, 2000); // 2秒后解决 Promise
});
}
// 定义一个 async 函数,使用 await 关键字等待 fetchData 函数的 Promise 解决
async function getData() {
console.log("开始获取数据...");
// await 会暂停 getData 函数的执行,直到 fetchData 返回的 Promise 解决
const data = await fetchData();
// 当 Promise 解决后,继续执行 getData 函数
console.log(data); // 输出 "数据已获取"
console.log("数据获取完成。");
}
// 调用 async 函数
getData();