快乐编程之旅:了解这20道JavaScript手写题助力提升开发内力

简介: 快乐编程之旅:了解这20道JavaScript手写题助力提升开发内力

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);
    }
  }
}


相关文章
|
9天前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
138 1
|
21天前
|
JavaScript 前端开发 NoSQL
深入浅出Node.js后端开发
本文将引导你了解Node.js的基础知识,包括安装、运行环境搭建以及简单的代码示例。通过阅读本文,你将学会如何利用Node.js进行后端开发,并理解异步编程和事件驱动模型的核心概念。文章还将介绍一些实用的库和框架,帮助你快速开始Node.js项目。
46 4
|
23天前
|
JavaScript 前端开发 开发者
VUE 开发——Node.js学习(一)
VUE 开发——Node.js学习(一)
47 3
|
25天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【9月更文挑战第35天】本文将带你走进Node.js的世界,从基础概念到实战应用,一步步揭示Node.js在后端开发中的魅力。我们将通过实际代码示例,让你轻松掌握Node.js的开发技巧,开启你的后端开发之旅。
|
13天前
|
JavaScript 前端开发 安全
TypeScript的优势与实践:提升JavaScript开发效率
【10月更文挑战第8天】TypeScript的优势与实践:提升JavaScript开发效率
|
13天前
|
JavaScript 前端开发 IDE
深入理解TypeScript:提升JavaScript开发的利器
【10月更文挑战第8天】 深入理解TypeScript:提升JavaScript开发的利器
24 0
|
1月前
|
存储 JavaScript 前端开发
JavaScript编程实现tab选项卡切换的效果+1
JavaScript编程实现tab选项卡切换的效果+1
|
21天前
|
前端开发 JavaScript 关系型数据库
前端的全栈之路:基于 Vue3 + Nest.js 全栈开发的后台应用
这篇文章介绍了一个名为Vue3Admin的全栈后台应用,前端基于SoybeanAdmin二次开发,后端基于Nest.js。主要使用了Vue3.5、AntDesignVue、UnoCSS、Pinia等前端技术栈,以及Nest.js、PostgreSQL、Prisma等后端技术栈。文章详细描述了系统的功能设计,包括动态国际化语言配置、登录用户操作日志、用户和角色权限映射、动态路由菜单、消息公告发布及前端业务功能等。同时,也提供了项目运行所需的环境和依赖,以及如何拉取代码、安装依赖和启动项目的方法。最后,文章展示了项目的演示图,并对项目进行了总结,指出项目未经严格测试,仅供学习交流使用。
前端的全栈之路:基于 Vue3 + Nest.js 全栈开发的后台应用
|
14天前
|
Web App开发 存储 JavaScript
深入浅出Node.js后端开发
【10月更文挑战第7天】本文将带你进入Node.js的世界,从基本概念、环境搭建到实际案例,逐步深入探索Node.js在后端开发中的应用。我们将通过一个简单的在线聊天室项目,学习如何利用Node.js进行网络编程和数据处理,让你对Node.js有更全面的认识。
15 3
|
17天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第4天】本文将带你走进Node.js的世界,从基础的搭建到高级的应用,一步步揭示Node.js的强大与便捷。我们将通过实际的代码示例,让你在轻松的氛围中学习并掌握Node.js,开启你的后端开发之旅。