花样手写18种 JavaScript 基本函数,附有详细解析
2024-02-23 22:07:32
花样手写18种 JavaScript 基本函数,附有详细解析
前言
JavaScript 作为一门强大的编程语言,在Web开发中扮演着重要角色。掌握JavaScript的基本函数是成为一名合格的前端开发人员的必备技能。本文将详细介绍如何手写 18 种 JavaScript 基本函数,包括 Object.create、instanceof、事件委托、深拷贝、防抖、节流、函数柯里化、函数组合、数组扁平化、数组去重、数组交集、数组并集、数组差集、对象转URL参数、URL参数转对象等。这些函数在实际开发中非常有用,掌握它们可以大大提高开发效率。
Object.create
手写 Object.create 方法的思路很简单,将传入的对象作为原型,创建一个新的对象。代码如下:
function Object.create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
instanceof
instanceof 运算符用于判断一个对象是否是某个构造函数的实例。手写 instanceof 方法的思路是,首先获取对象的原型,然后逐层向上查找,看看是否能找到与给定构造函数的原型相同的原型。如果能找到,则说明该对象是该构造函数的实例。代码如下:
function instanceof(obj, constructor) {
while (obj) {
if (obj === constructor.prototype) {
return true;
}
obj = obj.__proto__;
}
return false;
}
事件委托
事件委托是一种事件处理机制,它可以大大提高事件处理的效率。事件委托的思想是,将事件处理程序绑定到父元素,而不是子元素。这样,当子元素发生事件时,事件会沿着DOM树向上冒泡,最终到达父元素。父元素的事件处理程序可以处理所有子元素的事件,而无需为每个子元素单独绑定事件处理程序。代码如下:
const parent = document.getElementById('parent');
parent.addEventListener('click', (e) => {
// 处理所有子元素的点击事件
});
深拷贝
深拷贝是指将一个对象的所有属性和嵌套对象都复制一份,从而创建一个新的对象。手写深拷贝函数的思路是,使用递归的方式,遍历对象的每个属性,如果属性是对象,则继续递归复制,否则直接复制属性值。代码如下:
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const newObj = Array.isArray(obj) ? [] : {};
for (const key in obj) {
newObj[key] = deepCopy(obj[key]);
}
return newObj;
}
防抖
防抖函数是指,当一个函数被多次调用时,只执行最后一次调用。防抖函数的应用场景很多,比如输入框的实时搜索、窗口的滚动事件处理等。手写防抖函数的思路是,使用一个定时器来控制函数的执行。当函数被调用时,首先清除定时器,然后重新创建一个定时器。如果在定时器到期之前函数又被调用,则再次清除定时器,重新创建一个定时器。这样,只有当函数在一定时间内没有被调用时,才会真正执行。代码如下:
function debounce(func, wait) {
let timeout;
return function () {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
节流
节流函数是指,当一个函数被多次调用时,只执行一定时间间隔内的第一次调用。节流函数的应用场景很多,比如窗口的滚动事件处理、鼠标的移动事件处理等。手写节流函数的思路是,使用一个变量来记录上次函数执行的时间。当函数被调用时,首先检查上次函数执行的时间是否超过了指定的时间间隔。如果超过了,则执行函数,并更新上次函数执行的时间。否则,不执行函数。代码如下:
function throttle(func, wait) {
let lastTime = 0;
return function () {
const context = this;
const args = arguments;
const now = Date.now();
if (now - lastTime > wait) {
func.apply(context, args);
lastTime = now;
}
};
}
函数柯里化
函数柯里化是指,将一个函数的部分参数固定下来,生成一个新的函数。函数柯里化的应用场景很多,比如创建偏函数、创建通用函数等。手写函数柯里化的思路是,使用闭包来保存已经固定下来的参数。当柯里化函数被调用时,首先检查是否已经传入了所有参数。如果已经传入了所有参数,则直接执行函数。否则,返回一个新的柯里化函数,将已经固定下来的参数和新的参数一起保存起来。代码如下:
function curry(func) {
return function curryWrapper(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return curryWrapper.bind(this, ...args);
}
};
}
函数组合
函数组合是指,将多个函数组合起来,形成一个新的函数。函数组合的应用场景很多,比如创建管道函数、创建通用函数等。手写函数组合的思路是,使用闭包来保存已经组合好的函数。当组合函数被调用时,首先检查是否已经组合好了所有函数。如果已经组合好了,则直接执行函数。否则,返回一个新的组合函数,将已经组合好的函数和新的函数一起保存起来。代码如下:
function compose(...funcs) {
return function composed(...args) {
if (funcs.length === 0) {
return args[0];
}
const lastFunc = funcs[funcs.length - 1];
const restFuncs = funcs.slice(0, funcs.length - 1);
return restFuncs.reduceRight((composed, func) => {
return func(composed);
}, lastFunc(...args));
};
}
数组扁平化
数组扁平化是指,将一个多维数组转换成一个一维数组。数组扁平化的应用场景很多,比如创建扁平化的树结构、创建扁平化的列表等。手写数组扁平化的思路是,使用递归的方式,遍历数组的每个元素。如果元素是数组,则继续递归扁平化。否则,将元素添加到一维数组中。代码如下:
function flatten(arr) {
const newArr = [];
for (const item of arr) {
if (Array.isArray(item)) {
newArr.push(...flatten(item));
} else {
newArr.push(item);
}
}
return newArr;
}
数组去重
数组去重是指,将一个数组中的重复元素删除,只保留唯一的元素。数组去重的应用场景很多,比如创建不重复的列表、创建不重复的集合等。手写数组去重的思路是,使用 Set 数据结构来存储数组中的元素。Set 数据结构可以自动去除重复元素。代码如下:
function uniq(arr) {
return [...new Set(arr)];
}
数组交集
数组交集是指,找到两个数组中共同的元素。数组交集的应用场景很多,比如创建交集列表、创建交集集合等。手写数组交集的思路是,使用 Set 数据结构来存储其中一个数组的元素。然后,遍历另一个数组的每个元素,如果元素在 Set 数据结构中,则将元素添加到交集数组中。代码如下:
function intersection(arr1, arr2) {
const set1 = new Set(arr1);
const intersection = [];
for (const item of arr2) {
if (set1.has(item