1. 实现阶乘函数:
阶乘函数是一个常见的数学函数,用于计算一个非负整数的阶乘。阶乘表示从 1 到该整数之间所有整数的乘积。
以 n! 表示 n 的阶乘,其中 n 是一个非负整数。阶乘函数可以通过递归或循环来实现。
递归实现的阶乘函数如下:
function factorialRecursive(n) { if (n === 0 || n === 1) { return 1; } return n * factorialRecursive(n - 1); }
这个函数首先检查输入的整数是否为 0 或 1,因为它们的阶乘都是 1。对于其他大于 1 的整数 n,阶乘等于 n 乘以 (n-1) 的阶乘。
循环实现的阶乘函数如下:
function factorialIterative(n) { let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; }
这个函数使用一个循环从 2 开始迭代乘法,直到乘到 n。在每次迭代中,将当前结果与当前的整数相乘,并将乘积赋给结果变量。
无论是递归还是循环实现,阶乘函数都可以有效地计算任意非负整数的阶乘。
2. 实现数组平均值计算函数:
function calculateAverage(arr) { let sum = 0; for (let i = 0; i < arr.length; i++) { sum += arr[i]; } return sum / arr.length; }
3. 实现数组去重函数:
function removeDuplicates(arr) { return arr.filter((value, index, self) => self.indexOf(value) === index); }
4. 实现数组扁平化函数:
function flattenArray(arr) { return arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flattenArray(val) : val), []); }
数组扁平化是指将多维数组转换为一维数组的过程。在 JavaScript 中,我们可以使用递归或迭代的方式来实现数组的扁平化。
递归实现的数组扁平化函数如下:
function flattenRecursive(arr) { let result = []; for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { result = result.concat(flattenRecursive(arr[i])); } else { result.push(arr[i]); } } return result; }
这个函数通过遍历数组中的每个元素,如果当前元素是数组,则递归调用自身将其扁平化,并使用 concat
方法将扁平化后的结果与 result
数组合并。如果当前元素不是数组,则直接将其添加到 result
数组中。
迭代实现的数组扁平化函数如下:
function flattenIterative(arr) { const stack = [...arr]; const result = []; while (stack.length) { const curr = stack.pop(); if (Array.isArray(curr)) { stack.push(...curr); } else { result.unshift(curr); } } return result; }
这个函数使用一个堆栈数据结构来迭代地处理数组。我们首先将初始数组复制到堆栈中,然后循环执行以下操作:从堆栈中取出元素,如果当前元素是数组,则将其展开并推入堆栈中。如果当前元素不是数组,则将其添加到结果数组的开头。
这两种方法都可以将多维数组扁平化为一维数组。你可以根据自己的需求选择递归或迭代的方式来实现数组的扁平化。
5. 实现字符串反转函数:
function reverseString(str) { return str.split('').reverse().join(''); }
6. 实现对象深拷贝函数:
function deepCopy(obj) { return JSON.parse(JSON.stringify(obj)); }
7. 实现判断回文字符串函数:
function isPalindrome(str) { const reversed = str.split('').reverse().join(''); return str === reversed; }
8. 实现简单的节流函数:
节流函数在 JavaScript 中用于限制某个函数在一定时间间隔内执行的频率,以减少函数被过度触发的情况。通过节流函数,我们可以控制函数执行的频率,确保在指定的时间间隔内只执行一次。
以下是一个常见的节流函数的实现,使用了定时器来延迟函数的执行:
function throttle(func, delay) { let timerId; return function(...args) { if (!timerId) { func.apply(this, args); timerId = setTimeout(() => { timerId = null; }, delay); } }; }
这个函数接受两个参数:func
是需要进行节流处理的函数,delay
是指定的时间间隔(毫秒)。
节流函数返回了一个新的函数,该函数首先检查是否存在一个定时器ID。如果定时器ID不存在,则表示可以执行传入的函数,并设置一个定时器,在指定的延迟时间后将定时器ID清空,以便下次函数调用时可以再次执行。
这样,当函数被连续触发时,只有在指定的时间间隔过去后才会真正执行一次函数。这样可以有效地控制函数的触发频率,避免函数被过度调用。
示例用法:
function doSomething() { console.log("Doing something..."); } const throttledFunc = throttle(doSomething, 1000); // 在 1 秒内连续调用函数多次 throttledFunc(); // 函数被执行 throttledFunc(); // 函数被忽略 throttledFunc(); // 函数被忽略 // 1 秒后再次调用函数 setTimeout(() => { throttledFunc(); // 函数被执行 }, 1000);
在上面的示例中,doSomething
函数被传入 throttle
函数中,并使用 throttledFunc
作为节流处理后的函数。紧接着,连续调用了多次 throttledFunc
,但在指定的时间间隔内,只有第一次触发时函数真正执行了。在 1 秒后,再次调用 throttledFunc
,函数会再次被执行。
9. 实现数组排序函数:
function sortArray(arr) { return arr.sort((a, b) => a - b); }
10. 实现判断两个数组是否相等函数:
function arraysAreEqual(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) { return false; } } return true; }
11. 实现数组的map函数:
function myMap(arr, callback) { const result = []; for (let i = 0; i < arr.length; i++) { result.push(callback(arr[i], i, arr)); } return result; }
12. 实现数组的filter函数:
function myFilter(arr, callback) { const result = []; for (let i = 0; i < arr.length; i++) { if (callback(arr[i], i, arr)) { result.push(arr[i]); } } return result; }
13. 实现数组的reduce函数:
function myReduce(arr, callback, initialValue) { let accumulator = initialValue !== undefined ? initialValue : arr[0]; for (let i = initialValue !== undefined ? 0 : 1; i < arr.length; i++) { accumulator = callback(accumulator, arr[i], i, arr); } return accumulator; }
14. 实现数组的forEach函数:
function myForEach(arr, callback) { for (let i = 0; i < arr.length; i++) { callback(arr[i], i, arr); } }
15. 实现Promise的简单实现(仅包括resolve方法):
class MyPromise { constructor(executor) { this.value = undefined; this.state = 'pending'; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; executor(resolve); } then(callback) { if (this.state === 'fulfilled') { callback(this.value); } } }
16. 实现函数柯里化(Currying):
函数柯里化是一种将接受多个参数的函数转换为一系列接受单个参数的函数的过程。通过柯里化,我们可以将一个多参数函数转变为一个接受一个参数并返回一个新函数的函数链,每个新函数都接受下一个参数,并最终返回最终结果。
下面是一个示例,演示了如何实现函数柯里化:
function curry(fn) { return function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args); } else { return function (...nextArgs) { return curried.apply(this, args.concat(nextArgs)); }; } }; }
这个 curry
函数接受一个多参数函数 fn
作为参数,并返回一个柯里化后的函数。在返回的柯里化函数中,我们首先检查传入的参数数量是否达到原始函数 fn
的参数数量。如果是,则直接调用原始函数并返回结果。否则,返回一个新的函数,该函数接受剩余的参数,并通过递归调用将参数不断累积起来,直到参数数量足够触发原始函数的执行。
以下是一个使用函数柯里化的示例:
function add(a, b, c) { return a + b + c; } 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
在上面的示例中,我们使用 curry
函数将 add
函数柯里化为 curriedAdd
。然后,我们可以通过连续调用返回的函数,每次传入一个参数,最终得到结果。无论是一次性传入所有参数,还是分多次传入参数,都可以正确计算出最终结果。
函数柯里化可以以简洁的方式处理多参数函数,并且在函数复用和参数传递方面提供了灵活性。它在函数式编程中被广泛使用和应用。
17. 实现自定义的事件触发器:
class EventEmitter { constructor() { this.events = {}; } on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); } emit(eventName, ...args) { if (this.events[eventName]) { this.events[eventName].forEach(callback => callback.apply(null, args)); } } }
18. 实现深度优先搜索算法(DFS):
function dfs(node, callback) { callback(node); node.children.forEach(child => dfs(child, callback)); }
19. 实现广度优先搜索算法(BFS):
function bfs(root, callback) { const queue = [root]; while (queue.length > 0) { const node = queue.shift(); callback(node); queue.push(...node.children); } }
20. 实现一个简单的Event Bus:
class EventBus { constructor() { this.events = {}; } on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); } emit(eventName, ...args) { if (this.events[eventName]) { this.events[eventName].forEach(callback => callback.apply(null, args)); } } off(eventName, callback) { if (this.events[eventName]) { this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); } } }