宣传旅游网站建设的观点是什么,网站排名优化+o+m,网络设计是什么意思,深圳 网站托管目录 防抖节流高阶函数函数柯里化数组去重set去重filter去重includes去重 数组扁平化深拷贝getBoundingCilentRectIntersectionObserver自定义事件 防抖
防抖是一种常用的技术手段#xff0c;在JavaScript中特别常见。它的作用是控制某些高频率触发的事件#xff0c;在一定时… 目录 防抖节流高阶函数函数柯里化数组去重set去重filter去重includes去重 数组扁平化深拷贝getBoundingCilentRectIntersectionObserver自定义事件 防抖
防抖是一种常用的技术手段在JavaScript中特别常见。它的作用是控制某些高频率触发的事件在一定时间内只执行一次从而减少不必要的资源消耗。以下是一个防抖的案例
// 假设有一个输入框需要实时响应用户输入
const input document.querySelector(#input);
let timeout;function debounce(func, delay) {clearTimeout(timeout);timeout setTimeout(func, delay);
}// 当用户输入时触发的事件处理函数
function handleInput() {console.log(input.value);// 做其他操作...
}// 使用防抖来控制输入事件的触发频率
input.addEventListener(input, function() {debounce(handleInput, 300); // 在300毫秒内只执行一次handleInput函数
});在上面的示例中输入框的input事件会触发handleInput函数但是通过使用debounce函数在300毫秒内只会执行一次handleInput函数。这样可以避免频繁响应用户输入导致的性能问题。
防抖在实际开发中还有很多应用场景比如监听窗口大小改变、滚动事件等。通过合理地运用防抖技术可以提升用户体验和页面性能。
节流
节流是另一种常见的技术手段用于控制某些高频率触发的事件在一定时间间隔内执行一次。下面是一个节流的案例
// 假设有一个按钮点击时需要发送请求
const button document.querySelector(#button);
let canClick true;function throttle(func, delay) {if (canClick) {canClick false;setTimeout(function() {func();canClick true;}, delay);}
}// 点击事件的处理函数
function handleClick() {console.log(发送请求);// 做其他操作...
}// 使用节流来控制点击事件的触发频率
button.addEventListener(click, function() {throttle(handleClick, 1000); // 在1000毫秒内只执行一次handleClick函数
});在上面的示例中按钮的点击事件会触发handleClick函数但是通过使用throttle函数在1000毫秒内只会执行一次handleClick函数。这样可以避免频繁点击导致的重复请求或其他问题。
节流在实际开发中也有许多应用场景比如限制事件的触发频率如鼠标移动事件、滚动事件等。通过合理地运用节流技术可以控制事件的执行频率从而提升性能和用户体验。
高阶函数
高阶函数是指接收一个或多个函数作为参数并返回一个新的函数的函数。它在函数式编程中具有重要的作用可以用于实现函数的复用、组合和抽象等。以下是一个高阶函数的案例
// 假设有一个计算函数执行时间的高阶函数
function calculateExecutionTime(func) {return function() {const start performance.now();const result func.apply(this, arguments);const end performance.now();console.log(函数执行时间为${end - start}毫秒);return result;}
}// 普通的函数
function add(a, b) {return a b;
}// 使用高阶函数计算add函数的执行时间
const timedAdd calculateExecutionTime(add);// 调用新的函数
timedAdd(1, 2); // 输出函数执行时间为0.0249999229毫秒返回3在上面的示例中calculateExecutionTime是一个高阶函数它接收一个函数作为参数并返回一个新的函数。返回的新函数在执行时会先记录函数开始执行的时间然后调用原函数最后计算函数执行的时间并输出。
通过使用高阶函数我们可以复用calculateExecutionTime函数来计算其他函数的执行时间而无需重复编写计时逻辑。这提供了一种抽象和代码复用的机制提高了代码的可维护性和可读性。
除了计算执行时间在实际开发中还可以使用高阶函数来实现其他功能如错误处理、日志记录、缓存等。高阶函数为函数式编程提供了丰富的工具和思路。
函数柯里化
函数柯里化是一种将多参数函数转化为一系列单参数函数的技术使得函数更加灵活和可复用。以下是一个函数柯里化的案例
// 假设有一个加法函数
function add(a, b, c) {return a b c;
}// 使用函数柯里化将多参数函数转化为单参数函数
function curry(func) {return function curried(...args1) {if (args1.length func.length) {return func.apply(this, args1);} else {return function(...args2) {return curried.apply(this, args1.concat(args2));}}};
}// 对add函数进行柯里化
const curriedAdd curry(add);// 调用柯里化后的函数
console.log(curriedAdd(1)(2)(3)); // 输出6
console.log(curriedAdd(1, 2)(3)); // 输出6
console.log(curriedAdd(1)(2, 3)); // 输出6
console.log(curriedAdd(1, 2, 3)); // 输出6在上面的示例中curry是一个函数柯里化的高阶函数。它接收一个多参数函数作为参数并返回一个经过柯里化处理后的新函数。返回的新函数可以接收单个参数在参数收集到足够数量后就会执行原函数。
通过对add函数进行柯里化我们可以使用不同的方式来调用柯里化后的函数。不论是逐个传入参数还是一次传入多个参数最终都能得到正确的结果。
函数柯里化可以用于实现参数复用、函数组合以及延迟执行等功能。它提供了一种灵活的方式来处理函数和参数增强了代码的可读性和可维护性。
数组去重
set去重
使用ES6中的Set数据结构可以很方便地实现数组的去重操作。Set是一种无重复值的有序集合它只会存储唯一的值。下面是一个使用Set进行数组去重的案例
const array [1, 2, 3, 3, 4, 5, 5];
const uniqueArray [...new Set(array)];console.log(uniqueArray); // 输出[1, 2, 3, 4, 5]在上面的示例中我们定义了一个数组array其中包含了一些重复的元素。通过使用new Set(array)我们可以将数组转换为一个Set对象Set会自动去除重复的值。然后通过扩展运算符[...new Set(array)]将Set对象转化回数组就得到了去重后的uniqueArray。
需要注意的是Set返回的是一个迭代器对象而不是一个数组。为了将其转化回数组我们使用扩展运算符[...new Set(array)]将Set对象中的值取出并放入一个新的数组中。
这种方法简洁高效适用于基本类型和引用类型的数组。然而如果数组中的元素是复杂的对象则需要注意对象之间的引用关系因为Set进行去重是基于严格相等比较的。如果需要对复杂对象进行深度去重需要使用其他的方法。
filter去重
使用filter方法可以实现数组的去重操作。filter方法接收一个回调函数作为参数遍历数组的每个元素并根据回调函数的返回值决定是否保留该元素。下面是一个使用filter进行数组去重的案例
const array [1, 2, 3, 3, 4, 5, 5];
const uniqueArray array.filter((value, index, self) {return self.indexOf(value) index;
});console.log(uniqueArray); // 输出[1, 2, 3, 4, 5]在上面的示例中我们使用filter方法对数组array进行遍历对于每个元素我们通过indexOf方法判断在数组中第一次出现的索引是否和当前的索引相同。如果相同说明当前元素是第一次出现保留该元素否则过滤掉重复的元素。
通过这种方式filter方法会创建一个新的数组uniqueArray其中只包含不重复的元素。
需要注意的是indexOf方法在遇到引用类型的元素时可能无法正确判断是否重复因为引用类型的比较是基于引用地址的。在处理复杂对象的数组去重时可能需要使用其他方法如使用reduce方法结合自定义的比较函数进行去重操作。
includes去重
使用includes方法可以在数组中检查是否包含某个特定的元素。尽管includes方法本身并不能直接实现数组的去重但结合filter或其他数组方法可以间接地实现数组去重的效果。下面是一个使用includes进行数组去重的案例
const array [1, 2, 3, 3, 4, 5, 5];
const uniqueArray array.filter((value, index, self) {return self.indexOf(value) index self.includes(value);
});console.log(uniqueArray); // 输出[1, 2, 3, 4, 5]在上面的示例中我们使用filter方法对数组array进行遍历对于每个元素我们通过indexOf方法判断在数组中第一次出现的索引是否和当前的索引相同同时使用includes方法判断数组中是否包含当前的元素。如果满足这两个条件就保留该元素即实现了去重操作。
通过结合使用indexOf和includes方法我们可以在保留数组中第一个出现的重复元素的同时过滤掉其余的重复元素从而得到去重后的uniqueArray。
需要注意的是与上述提到的方法一样当处理复杂对象的去重时需要使用其他的方法来进行深度比较并根据具体需求来实现去重的逻辑。
数组扁平化
数组扁平化指的是将多层嵌套的数组转化为一层的数组。这种操作可以简化数组的处理和遍历过程。下面介绍几种实现数组扁平化的常用方法 使用Array.prototype.flat方法ES2019 const nestedArray [1, [2, [3, 4]]];
const flattenedArray nestedArray.flat(Infinity);console.log(flattenedArray); // 输出[1, 2, 3, 4]flat方法接收一个可选的扁平化深度参数默认为1。通过传递Infinity作为参数可以完全扁平化多层嵌套的数组。 使用递归和concat方法 function flattenArray(array) {let flattenedArray [];array.forEach(item {if (Array.isArray(item)) {flattenedArray flattenedArray.concat(flattenArray(item));} else {flattenedArray.push(item);}});return flattenedArray;
}const nestedArray [1, [2, [3, 4]]];
const flattenedArray flattenArray(nestedArray);console.log(flattenedArray); // 输出[1, 2, 3, 4]上述代码中flattenArray函数通过递归地处理每个元素如果元素是数组则继续递归地扁平化如果不是数组则直接将元素加入到结果数组中。 使用reduce方法 function flattenArray(array) {return array.reduce((result, item) {if (Array.isArray(item)) {return result.concat(flattenArray(item));} else {return result.concat(item);}}, []);
}const nestedArray [1, [2, [3, 4]]];
const flattenedArray flattenArray(nestedArray);console.log(flattenedArray); // 输出[1, 2, 3, 4]reduce方法通过遍历数组的每个元素将元素累积到一个结果数组中。如果元素是数组则递归地扁平化后再进行累积如果元素不是数组则直接累积到结果数组中。
无论通过哪种方法实现数组扁平化都可以将多层嵌套的数组转化为一层的数组便于后续的处理和操作。
深拷贝
深拷贝是指创建一个完全独立于原始对象的副本包括所有嵌套的对象和数组。深拷贝确保修改副本不会影响原始对象。下面介绍几种常见的实现深拷贝的方法 使用 JSON 序列化与反序列化 const originalObj { a: 1, b: { c: 2 } };
const clonedObj JSON.parse(JSON.stringify(originalObj));console.log(clonedObj); // 输出{ a: 1, b: { c: 2 } }通过先将原始对象转换为JSON字符串然后使用JSON.parse方法将字符串转换回对象就能实现深拷贝。这种方法适用于大多数可以转换为JSON的数据类型但它存在一些限制比如无法拷贝函数、循环引用等。 使用递归实现深拷贝 function deepClone(obj) {if (typeof obj ! object || obj null) {return obj; // 处理基本类型和null}let clonedObj Array.isArray(obj) ? [] : {}; // 创建与原始对象类型相同的空对象或空数组for (let key in obj) {if (obj.hasOwnProperty(key)) {clonedObj[key] deepClone(obj[key]); // 递归调用深拷贝}}return clonedObj;
}const originalObj { a: 1, b: { c: 2 } };
const clonedObj deepClone(originalObj);console.log(clonedObj); // 输出{ a: 1, b: { c: 2 } }上述代码中deepClone函数使用递归实现深拷贝。它遍历原始对象的每个属性并对属性值进行递归调用以确保所有嵌套的对象和数组也被深拷贝。 使用第三方库实现深拷贝 在 JavaScript 社区中有许多流行的第三方库如lodash、underscore等提供了方便的深拷贝函数。这些库通常具有更复杂的逻辑可以处理各种特殊情况并提供更高级的拷贝功能。你可以选择其中一个库根据其文档使用深拷贝函数。
无论使用哪种方法深拷贝都可以创建一个原始对象的完全独立副本。需要注意的是在处理特殊对象类型如函数、正则表达式、循环引用等时需要特别留意深拷贝的实现方式。
getBoundingCilentRect
getBoundingClientRect 是一个 DOM 元素方法用于获取元素的大小和位置信息。它返回一个 DOMRect 对象其中包含了与元素相关的位置、宽度、高度等属性。下面是一个使用 getBoundingClientRect 方法的示例
const element document.getElementById(myElement);
const rect element.getBoundingClientRect();console.log(rect); // 输出DOMRect 对象
console.log(rect.width); // 输出元素的宽度
console.log(rect.height); // 输出元素的高度
console.log(rect.top); // 输出元素顶部相对于视口的距离
console.log(rect.bottom); // 输出元素底部相对于视口的距离
console.log(rect.left); // 输出元素左侧相对于视口的距离
console.log(rect.right); // 输出元素右侧相对于视口的距离在上述示例中我们通过 getElementById 方法获取到一个 DOM 元素并将其赋值给变量 element。然后我们使用 getBoundingClientRect 方法获取该元素的大小和位置信息并将结果保存在 rect 变量中。
接下来我们可以通过 rect 对象获取元素的各种属性如 width、height、top、bottom、left 和 right。这些属性提供了元素相对于视口的位置和尺寸信息可以在计算布局或进行其他各种操作时使用。
需要注意的是getBoundingClientRect 方法返回的是一个只读的 DOMRect 对象它在每次调用时都会重新计算元素的位置和尺寸。如果元素的样式或布局发生变化需要重新调用 getBoundingClientRect 方法以获取最新的信息。此外返回的值是相对于视口的位置而不是相对于文档的位置。如果需要相对于文档的位置可以通过加上 window.scrollX 和 window.scrollY 来计算。
IntersectionObserver
Intersection Observer 是一个新的 JavaScript API用于异步观察目标元素与其祖先元素或文档视口之间的交叉状态。它可以用于检测目标元素是否进入、退出或部分可见于其祖先元素或视口。
使用 Intersection Observer 的主要目的是观察元素的可见性而无需连续监测和处理滚动事件。这在需要有效地处理大量元素或需要实时响应元素可见性变化的情况下非常有用。
下面是一个使用 Intersection Observer 的简单示例
// 创建一个 Intersection Observer 实例
const observer new IntersectionObserver(entries {entries.forEach(entry {if (entry.isIntersecting) {console.log(目标元素可见);} else {console.log(目标元素不可见);}});
});// 监听目标元素
const targetElement document.querySelector(#myElement);
observer.observe(targetElement);在上述示例中我们首先创建了一个 Intersection Observer 实例 observer通过构造函数传入一个回调函数。回调函数会在监听的目标元素进入或退出视口时被触发它接收一个包含交叉信息的 entries 数组。
然后我们选择要观察的目标元素并使用 observe 方法将其添加到 Intersection Observer 实例中进行监测。当目标元素进入或退出视口时回调函数将根据 entry.isIntersecting 属性判断目标元素的可见性并输出相应的信息。
除了上述示例中的基本用法Intersection Observer 还提供了更多功能如设置阈值、使用根元素、观察多个目标元素等。你可以参考相关文档深入了解 Intersection Observer 的更多用法和选项。
自定义事件
在 JavaScript 中你可以创建自定义事件来实现自定义的事件处理逻辑。自定义事件使你能够在代码中触发和订阅特定的事件并在需要时执行相应的操作。下面是一个简单的示例来演示如何创建和使用自定义事件
// 创建自定义事件对象
const customEvent new Event(myEvent);// 监听自定义事件
document.addEventListener(myEvent, () {console.log(自定义事件被触发);
});// 触发自定义事件
document.dispatchEvent(customEvent);在上面的示例中我们首先创建了一个自定义事件对象 customEvent通过 Event 构造函数传入事件名称。然后我们使用 addEventListener 方法在文档上订阅了 myEvent 事件并定义了事件处理程序。最后通过 dispatchEvent 方法在文档上触发了自定义事件。
当自定义事件被触发时事件处理程序就会执行并输出相应的消息到控制台上。
此外你还可以向自定义事件对象添加更多的数据以便在事件处理程序中使用。你可以使用 CustomEvent 构造函数来创建带有自定义数据的事件对象。例如
// 创建带有自定义数据的事件对象
const customEvent new CustomEvent(myEvent, {detail: {message: Hello, world!}
});// 监听自定义事件
document.addEventListener(myEvent, event {console.log(event.detail.message); // 输出Hello, world!
});// 触发自定义事件
document.dispatchEvent(customEvent);在上述示例中我们使用 CustomEvent 构造函数来创建自定义事件对象并通过 detail 属性添加了一个 message 属性。在事件处理程序中我们可以通过访问 event.detail 来获取传递的自定义数据。
通过自定义事件你可以根据需要定义和触发特定的事件以实现更灵活和定制化的事件处理逻辑。