技能六 自己封装防抖和节流
在前端开发中,防抖(Debounce)和节流(Throttle)函数同样是常用的技术,用于处理频繁触发的事件。下面是在前端中自己封装防抖和节流函数的示例代码
1. 防抖函数:
防抖函数的作用是在触发事件后,等待一定时间后执行对应的函数,如果在等待时间内再次触发了该事件,则重新计时。
function debounce(func, wait) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
使用示例
function handleInput(inputText) {
console.log("Handling input:", inputText);
}
const debouncedHandleInput = debounce(handleInput, 1500); // 设置等待时间为1.5秒
// 模拟触发事件
debouncedHandleInput("First input");
setTimeout(() => {
debouncedHandleInput("Second input"); // 不会立即执行
}, 1000);
setTimeout(() => {
debouncedHandleInput("Third input"); // 1.5秒后执行
}, 2000);
2. 节流函数
节流函数的作用是在一定时间间隔内,稀释事件的触发频率,确保函数在指定时间间隔内最多只执行一次。
function throttle(func, wait) {
let isThrottled = false;
return function (...args) {
if (isThrottled) return;
isThrottled = true;
func.apply(this, args);
setTimeout(() => {
isThrottled = false;
}, wait);
};
}
使用示例
function handleScroll(position) {
console.log("Handling scroll at position:", position);
}
const throttledHandleScroll = throttle(handleScroll, 2000); // 设置时间间隔为2秒
// 模拟触发事件
window.addEventListener("scroll", function () {
throttledHandleScroll(window.scrollY);
});
技能七 写一段导致内存泄漏的代码
下面是一个可能导致内存泄漏的前端代码示例:
function createLeak() {
const element = document.createElement("div");
// 添加事件监听器
element.addEventListener("click", function() {
console.log("Element clicked!");
});
// 将元素追加到文档中
document.body.appendChild(element);
}
// 定期调用 createLeak 函数
setInterval(createLeak, 1000);
这段代码在每次调用createLeak函数时,会创建一个新的 <div> 元素,并将一个匿名函数作为点击事件的监听器绑定到元素上。然后,它将这个元素追加到文档的 <body> 中。在每次函数调用之后,会设置一个定时器,每秒钟调用一次createLeak函数。
问题在于,每次调用createLeak函数时,都会创建一个新的元素和对应的事件监听器。这意味着随着时间的推移,页面中会存在越来越多的元素和事件监听器,而这些元素和监听器都没有被正确地清理和释放。如果这个过程持续进行,就会导致内存泄漏,因为被创建的元素和监听器会占用越来越多的内存,而无法被垃圾回收机制回收。
为了避免内存泄漏,应该在不再需要元素和事件监听器时进行正确的清理。在这个例子中,可以在元素不再需要时,使用removeEventListener方法将事件监听器从元素上移除,以及使用removeChild方法将元素从文档中移除。
下面是修复后的代码示例:
function createLeak() {
const element = document.createElement("div");
element.addEventListener("click", function() {
console.log("Element clicked!");
});
document.body.appendChild(element);
// 清理函数
function cleanup() {
element.removeEventListener("click", handleClick);
document.body.removeChild(element);
}
// 一段时间后执行清理
setTimeout(cleanup, 5000);
}
setInterval(createLeak, 1000);
在修复后的代码中,添加了一个名为cleanup的清理函数。在每次创建元素时,会为该元素设置一个定时器,在一定时间后调用cleanup函数,以便正确地清理元素和事件监听器。在cleanup函数中,使用removeEventListener将事件监听器从元素上移除,并使用removeChild将元素从文档中移除。这样,不再需要的元素和事件监听器将被正确地清理和释放,避免了内存泄漏问题。
技能八 封装一个支持下标为负数的数组
在 JavaScript 中,默认的数组索引是从 0 开始的正整数。如果需要封装一个支持负数下标的数组,可以使用 JavaScript 的类来实现。下面是一个示例:
class CustomArray {
constructor() {
this.data = [];
}
get(index) {
if (index >= 0) {
return this.data[index];
} else {
const realIndex = this.data.length + index;
return this.data[realIndex];
}
}
set(index, value) {
if (index >= 0) {
this.data[index] = value;
} else {
const realIndex = this.data.length + index;
this.data[realIndex] = value;
}
}
}
// 示例用法
const arr = new CustomArray();
arr.set(-1, "Last element");
console.log(arr.get(-1)); // 输出: "Last element"
arr.set(-2, "Second last element");
console.log(arr.get(-2)); // 输出: "Second last element"
在这个示例中,CustomArray 类封装了一个普通的数组 this.data。为了支持负数下标,get 和 set 方法首先判断传入的索引值是否为正数。如果是正数,则直接使用该索引访问数组;如果是负数,则将其转换为相应的真实索引,即 this.data.length + index。这样,就可以通过负数下标访问数组,并且与正数下标一样操作数组元素。
请注意,这只是一个简单的示例,仅供参考。在实际的应用中,你可能还需要实现其他数组的方法,如 push、pop、splice 等,以便更好地支持负数下标的数组操作。
技能九 使用mimin技术来复用代码
在前端开发中,MIMIN(Mixin, Inheritance, Mixin, Inheritance, and Normalization)技术可以用来实现代码的复用。MIMIN结合了继承和混合(mixin)的概念,以及一些标准化的实践,帮助开发者在不引入重复代码的情况下实现代码复用。下面将简要介绍MIMIN技术的概念和如何在前端使用它来复用代码。
1. 混合(Mixin):
混合是指将一个或多个对象的属性和方法合并到另一个对象中,从而实现代码的复用。在JavaScript中,可以使用Object.assign()方法或扩展运算符...来实现混合。
示例:
const mixin = {
logMessage() {
console.log("Mixin: Hello, world!");
}
};
const obj = {};
Object.assign(obj, mixin); // 将mixin的属性和方法混合到obj中
obj.logMessage(); // 输出: Mixin: Hello, world!
2. 继承(Inheritance):
继承是指通过创建子类从父类继承属性和方法,从而实现代码的复用。在JavaScript中,可以使用class关键字和extends关键字来实现继承。
示例:
class Parent {
logMessage() {
console.log("Parent: Hello, world!");
}
}
class Child extends Parent {
// 子类继承了父类的logMessage方法
}
const obj = new Child();
obj.logMessage(); // 输出: Parent: Hello, world!
3. 标准化(Normalization):
标准化是指在实现代码复用时,采用一致的命名和结构,以及遵循最佳实践和设计原则,使代码更易于维护和理解。
示例:
class Parent {
logMessage() {
console.log("Parent: Hello, world!");
}
}
const mixin = {
logMessage() {
console.log("Mixin: Hello, world!");
}
};
class Child extends Parent {
// 子类继承了父类的logMessage方法
}
const obj1 = new Parent();
const obj2 = new Child();
obj1.logMessage(); // 输出: Parent: Hello, world!
obj2.logMessage(); // 输出: Parent: Hello, world!
通过使用MIMIN技术,可以将混合和继承结合起来,实现更灵活和高效的代码复用。通过标准化实践,可以使代码更具可读性和可维护性。需要根据具体需求和场景选择合适的复用方式,并在代码设计和组织中遵循最佳实践和设计原则。
技能十 如何覆盖ele组件的样式
在前端开发中,覆盖Ele(Element UI)组件库的样式可以通过以下几种方式实现:
1. 使用全局样式:
你可以在全局的CSS样式文件中覆盖Ele组件的样式。通过在你的项目中创建一个具有更高优先级的样式规则,可以覆盖Ele组件默认样式。
示例:
/* 全局样式文件 */
/* 覆盖Ele组件的样式 */
.el-button {
background-color: red;
color: white;
}
.el-input {
border: 1px solid blue;
}
在上述示例中,我们使用了.el-button和.el-input选择器来覆盖Ele按钮和输入框组件的样式。你可以根据需要修改相应的样式属性。
2. 使用CSS Modules:
如果你在项目中使用了CSS Modules,你可以在组件的样式文件中定义覆盖Ele组件样式的规则。
示例:
/* 组件样式文件(使用CSS Modules) */
/* 覆盖Ele组件的样式 */
.my-button {
background-color: red;
color: white;
}
.my-input {
border: 1px solid blue;
}
在组件中引入样式并应用到对应的元素上:
<template>
<div>
<el-button class="my-button">Custom Button</el-button>
<el-input class="my-input"></el-input>
</div>
</template>
<style scoped module>
/* 引入样式 */
@import "./styles.css";
/* 应用样式 */
.my-button {
composes: el-button from "element-ui";
}
.my-input {
composes: el-input from "element-ui";
}
</style>
在上述示例中,我们在组件样式文件中定义了.my-button和.my-input规则来覆盖Ele按钮和输入框组件的样式。然后,在组件的样式标签中通过composes关键字将Ele组件的样式应用到自定义样式类上。
3. 使用/deep/选择器或>>>选择器:
在某些情况下,你可能需要在组件内部的样式中覆盖Ele组件的样式。你可以使用/deep/选择器(或>>>选择器)来穿透组件的样式边界,达到覆盖组件样式的目的。
示例:
<template>
<div>
<el-button class="custom-button">Custom Button</el-button>
<el-input class="custom-input"></el-input>
</div>
</template>
<style scoped>
/* 使用/deep/选择器或>>>选择器覆盖Ele组件的样式 */
.custom-button /deep/ .el-button {
background-color: red;
color: white;
}
.custom-input /deep/ .el-input {
border: 1px solid blue;
}
</style>
在上述示例中,我们使用了/deep/选择器来穿透组件的样式边界,并覆盖了Ele按钮和输入框组件的样式。你可以根据需要修改相应的样式属性。
请注意,在使用/deep/选择器或>>>选择器时,要确保样式选择器的权重足够高,以便覆盖Ele组件的默认样式。
以上是几种常见的方式来覆盖Ele组件的样式。你可以根据具体的需求和项目的样式架构选择适合的方法来进行样式覆盖。