前端面试常见手写代码题【详细篇】

news2024/10/8 19:37:16

文章目录

    • 前言:
    • 防抖
    • 节流
    • 函数柯里化
    • 函数组合
    • instanceof 实现
    • 实现new操作符的行为
    • 深拷贝
    • 继承实现:
    • 手写Promise
    • 数组中常见函数的实现

前言:

在前端面试中,经常会遇到要求手写的代码的题目,主要是考察我们的编程能力、和对JavaScript的理解以及对前端最佳实践的掌握。下面是我整理了一些常见的手写代码题目,您可以看看自己能实现哪些。。

防抖

防抖函数,确保一段时间内多次触发事件只执行一次。

// --- 基础版
function debounce(fn, delay) {
  let timer = 0;
  return (e) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => fn(e), delay);
  };
}
let deboundceCli = debounce((e) => console.log(e), 500);
document.body.addEventListener("click", function () {
  deboundceCli("执行了。");
});
// ---立即执行版
function debounceImmediate(fn, delay, immediate) {
  let timer = null;
  return (...rest) => {
    if (timer) {
      clearTimeout(timer);
    }

    // 立即执行
    if (immediate) {
      let exec = !timer;
      timer = setTimeout(() => (timer = null), delay);
      if (exec) {
        fn(...rest);
      }
    } else {
      timer = setTimeout(() => fn(...rest), delay);
    }
  };
}

let deboundceCli = debounceImmediate((e) => console.log(e), 500, true);
document.body.addEventListener("click", function () {
  deboundceCli("执行了。");
});

节流

节流函数,确保在指定时间内只执行一次。

const throttle = (fn, delay) => {
  let lastTimer = null;
  return (e) => {
    if (Date.now() - lastTimer > delay) {
      lastTimer = Date.now();
      fn(e);
    }
  };
};
let throttleCli = throttle((e) => console.log(e), 1000);
window.document.addEventListener("scroll", function () {
  throttleCli("执行了。。 ");
});

函数柯里化

能够接受多个参数,并返回一个新的函数。

// ---柯里化
const curry = (fn) => {
  return function inner() {
    let len = arguments.length;
    if (len === fn.length) {
      // 执行
      return fn(...arguments);
    } else {
      // 返回一个函数
      return (...res) => inner(...[...arguments, ...res]);
    }
  };
};

const f1 = (a, b, c) => a * b * c;

let cy = curry(f1);
console.log(cy(2)(3, 4)); // 24

函数组合

接受多个函数,返回新的函数,执行结果是从右向左执行

// ---- 函数组合---  从右向左执行
const group = (...rest) => {
  return (val) => {
    return [...rest].reduceRight((item, res) => {
      return res(item);
    }, val);
  };
};

const f1 = (val) => val + 5;
const f2 = (val) => val * 10;

let res = group(f1,f2)
console.log(res(10));  // 105: (10*10) + 5

instanceof 实现

根据原型链向上查找,如果找到null都还没找到,就返回false, 找到就返回 true

const my_instanceof = (instance, obj) => {
  let proto = instance.__proto__;
  while (proto) {
    if (proto.constructor.name === obj.name) return true;
    proto = proto.__proto__;
  }
  return false;
};

let a = [];

console.log("instanceOf 结果:", my_instanceof(a, Array));

实现new操作符的行为

function myNew(fn, ...args) {
    // 1. 创建一个空对象
    let obj = Object.create(fn.prototype);
    // 2. 调用构造函数,绑定this,并传入参数
    let result = fn.apply(obj, args);
    // 3. 如果构造函数返回了一个新的对象,则返回该对象;否则返回步骤1创建的对象
    return result instanceof Object ? result : obj;
}

深拷贝

处理基本数据类型,对象、数组以及其中的嵌套结构


function deepClone(obj) {
  // 如果是基本数据类型或null,则直接返回
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  // 如果是日期对象,则创建一个新的日期对象
  if (obj instanceof Date) {
    return new Date(obj);
  }
  // 如果是正则对象,则创建一个新的正则对象
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }
  // 创建一个新对象或数组,并存储在WeakMap中
  const cloneObj = new obj.constructor();

  // 递归拷贝原对象的每个属性
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 忽略原型链上的属性
      cloneObj[key] = deepClone(obj[key]);
    }
  }
  return cloneObj;
}

继承实现:

  • 5种JS原型继承方式总结,你了解几种?

手写Promise

  • 手写Promise 一、二

数组中常见函数的实现

在 JavaScript 中,数组的函数式方法非常强大,它们允许你以声明式的方式处理数组数据.

设置全局变量numbers

const numbers = [1, 2, 3];
  1. map
    map 方法创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值。

    Array.prototype.myMap = function (callback) {
      const newArray = [];
      for (let i = 0; i < this.length; i++) {
        newArray.push(callback(this[i], i, this));
      }
      return newArray;
    };
    
    const squares = numbers.myMap((number) => number * number);
    console.log(squares); // 输出 [1, 4, 9]
    
  2. filter
    filter 方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。

    Array.prototype.myFilter = function (callback) {
      const newArray = [];
      for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
          newArray.push(this[i]);
        }
      }
      return newArray;
    };
    
    const evens = numbers.myFilter((number) => number % 2 === 0);
    console.log(evens); // 输出 [2]
    
  3. reduce
    reduce 方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值,需要处理默认值

    Array.prototype.myReduce = function (callback, initialValue) {
      let accumulator = initialValue !== undefined ? initialValue : this[0];
      for (let i = initialValue !== undefined ? 0 : 1; i < this.length; i++) {
        accumulator = callback(accumulator, this[i], i, this);
      }
      return accumulator;
    };
    
    const sum = numbers.myReduce(
      (accumulator, currentValue) => accumulator + currentValue
    );
    console.log(sum); // 输出 6
    
  4. forEach
    forEach 方法对数组的每个元素执行一次提供的函数。

    Array.prototype.myForEach = function (callback) {
      for (let i = 0; i < this.length; i++) {
        callback(this[i], i, this);
      }
    };
    
    numbers.myForEach((number) => console.log(number));
    // 输出:
    // 1
    // 2
    // 3
    
  5. find
    find 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

    Array.prototype.myFind = function (callback) {
      for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
          return this[i];
        }
      }
      return undefined;
    };
    
    const found = numbers.myFind((number) => number > 1);
    console.log(found); // 输出 2
    
  6. every
    every 方法测试所有元素是否都通过了测试函数。如果都通过,则返回 true;否则返回 false。

    Array.prototype.myEvery = function (callback) {
      for (let i = 0; i < this.length; i++) {
        if (!callback(this[i], i, this)) {
          return false;
        }
      }
      return true;
    };
    
    const allAreNumbers = numbers.myEvery(
      (element) => typeof element === "number"
    );
    console.log(allAreNumbers); // 输出 true
    
  7. some
    some 方法测试数组中是不是至少有一个元素通过了被提供的函数测试。如果是,立即返回 true;否则返回 false。

    Array.prototype.mySome = function (callback) {
      for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
          return true;
        }
      }
      return false;
    };
    
    const anyAreEven = numbers.mySome((number) => number % 2 === 0);
    console.log(anyAreEven); // 输出 true
    
  8. flat
    flat 方法将嵌套的数组“拍平”,拍平的层级取决于输入的deep 深度

递归实现:

const flat = (arr, deep = 0) => {
  let result = [];

  if (deep === 0) return arr;

  arr.forEach((item) => {
    if (item instanceof Array) { 
      result = result.concat(flat(item, deep - 1));
    } else {
      result = result.concat(item);
    }
  });

  return result;
};

console.log(flat([1, 2, [3, 4, [5, 6]]], 1)); // [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log(flat([1, 2, [3, 4, [5, 6]]], 2)); // [ 1, 2, 3, 4, 5, 6 ]
Array.prototype.myFlat = function (depth = 1) {
  if (depth === 0) return this;

  return this.reduce((acc, val) => {
    return acc.concat(Array.isArray(val) ? val.myFlat(depth - 1) : val);
  }, []);
};

const nestedArray = [1, [2, 3, [2, 4, [5]]]];
const flatArray = nestedArray.myFlat(2);
console.log(flatArray); // 输出 [1, 2, 3, 2, 4, Array(1)]
  1. reduceRight
    reduceRight 方法对数组中的每个元素执行一个由您提供的 reducer 函数(从右到左执行),将其结果汇总为单个返回值。需要处理默认值

    Array.prototype.myReduceRight = function (callback, initialValue) {
      let accumulator =
        initialValue !== undefined ? initialValue : this[this.length - 1];
      let start = initialValue !== undefined ? this.length - 1 : this.length - 2;
      for (let i = start; i >= 0; i--) {
        accumulator = callback(accumulator, this[i], i, this);
      }
      return accumulator;
    };
    
    const rightSum = numbers.myReduceRight(
      (accumulator, currentValue) => accumulator + currentValue
    );
    console.log(rightSum); // 输出 6
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2197079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

八大排序--05堆排序

假设数组 arr[] {5,7,4,2,0,3,1,6},请通过插入排序的方式&#xff0c;实现从小到大排列&#xff1a; 方法&#xff1a;①利用完全二叉树构建大顶堆&#xff1b; ②对顶元素和堆底元素进行交换&#xff0c;除堆底元素之外其余元素继续构造大顶堆&#xff1b; ③重复步骤②&…

2k1000LA iso 镜像的制作

问题: 已经有了buildroot ,内核也调试好了,但是没有loongnix 镜像。 首先是网上下载镜像,看看能不能用 首先是现在 网上的 iso 镜像进行烧写测试。 安装 7z 解压软件 进行U盘的烧写。 进行系统安装测试: <

视频剪辑软件推荐电脑版:这5款剪辑软件不容错过!

在视频剪辑领域&#xff0c;选择合适的软件至关重要。不同的软件各有千秋&#xff0c;有的简单易用&#xff0c;适合新手快速上手&#xff1b;有的功能强大&#xff0c;适合专业团队进行深度编辑。以下是一些电脑版视频剪辑软件的推荐&#xff0c;涵盖了从新手到专业级别的不同…

【RAG】HiQA:一种用于多文档问答的层次化上下文增强RAG

前言 文档领域的RAG&#xff0c;之前的工作如ChatPDF等很多的RAG框架&#xff0c;文档数量一旦增加&#xff0c;将导致响应准确性下降&#xff0c;如下图&#xff1b;现有RAG方法在处理具有相似内容&#xff08;在面对大量难以区分的文档时&#xff09;和结构的文档时表现不佳…

人才画像系统是什么?有哪些功能和作用?

人才画像系统是一种先进的人力资源管理工具&#xff0c;它运用大数据和人工智能技术对员工的多方面特征进行深度分析。系统通过汇聚个人的教育背景、工作经验、技能掌握、性格特质及行为数据等信息&#xff0c;结合数据挖掘和机器学习算法&#xff0c;构建出每位员工的数字化“…

openEuler 22.03 (LTS-SP3)上安装mysql8单机版

一、目标 在openEuler 22.03 (LTS-SP3) 上安装 mysql 8.0.23 单机版 二、安装 1、下载二进制包 MySQL :: Download MySQL Community Server (Archived Versions) 下载页面 下载链接 https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.23-linux-glibc2.12-x86…

新生培训 day1 C语言基础 顺序 分支 循环 数组 字符串 函数

比赛地址 b牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ C语言数据类型 字符 整型数 int 2e9 long long 9e18 浮点数 代码示例 /** Author: Dduo * Date: 2024-10-8* Description: 新生培训day1 */ #include <stdio.h>int main() {// 定义变量in…

【2024.10.8练习】宝石组合

题目描述 题目分析 由于是求最值&#xff0c;原本考虑贪心&#xff0c;但由于算式过于复杂&#xff0c;首先考虑对算式化简。 进行质因数分解&#xff1a; 因此: 不妨设对于每个&#xff0c;&#xff0c;则上式可化简为&#xff1a; 即 用Vene图也可以求出同样结果。 可是以…

DepthB2R靶机打靶记录

一、靶机介绍 下载地址&#xff1a;https://download.vulnhub.com/depth/DepthB2R.ova 二、信息收集 根据靶机主页显示&#xff0c;确认靶机ip为192.168.242.132 端口扫描 nmap -p- -A 192.168.242.132 发现只开放了8080端口 用dirsearch扫个目录 apt-get update apt-get …

胤娲科技:机械臂「叛逃」记——自由游走,再悄然合体

夜深人静&#xff0c;你正沉浸在梦乡的前奏&#xff0c;突然意识到房间的灯还亮着。此刻的你&#xff0c;是否幻想过有一只无形的手&#xff0c;轻盈地飘过&#xff0c;帮你熄灭那盏碍眼的灯&#xff1f; 又或者&#xff0c;你正窝在沙发上&#xff0c;享受电视剧的紧张刺激&am…

RKMEDIA画面质量调节-QP调节

QP是在视频采集编码过程中的量化参数&#xff0c;其值与画面质量成反比&#xff0c;即QP值越大画面质量越小&#xff0c;其具体调整方法如下&#xff1a; typedef struct rkVENC_RC_PARAM_S {RK_U32 u32ThrdI[RC_TEXTURE_THR_SIZE]; // [0, 255]RK_U32 u32ThrdP[RC_TEXTURE_TH…

一致性哈希算法解析

1. 哈希算法 想象我们的网络世界是一个巨大的环形摩天轮&#xff0c;上面有无数的座位&#xff0c;每个座位都代表了一个存储空间。现在&#xff0c;我们需要将三万张照片安排到这个摩天轮的三台机器上。这些机器我们可以想象成三个大车厢&#xff0c;每个车厢可以装载一部分照…

GIS专业的就业前景

地理信息系统&#xff08;GIS&#xff09;作为一门跨学科的领域&#xff0c;随着技术的发展和应用领域的拓宽&#xff0c;其就业前景日益广阔。GIS专业毕业生可以在多个行业中找到合适的职位&#xff0c;并且随着经验的积累&#xff0c;薪资和职业发展空间都相当可观。 1. 就业…

怎么把图片压缩小一点?几个小技巧帮助你轻松压缩图片大小

怎么把图片压缩小一点&#xff1f;几个小技巧帮助你轻松压缩图片大小 压缩图片大小是许多用户在处理照片时的常见需求&#xff0c;特别是在需要上传图片到网页、发送电子邮件或储存时&#xff0c;减小文件大小可以大大提高效率。以下是五款可以帮助你轻松压缩图片大小的软件&a…

能不能给我讲讲redis中的列表

写在文章开头 本文将从redis源码的角度直接分析列表操作指令,因为大部分指令操作细节区别不是很大,同时为了更专注于列表逻辑的分析,所以本文笔者将以双向链表这个数据结构为核心对lrange、lindex、llen、rpush、lpop几个操作展开介绍,希望对你有帮助。 Hi,我是 sharkChi…

泛微OA设置多个人力资源审批人员

泛微OA设置节点审批人员在不同条件下必须都审批才能过流程 在泛微OA中设置审批人员可以有多个设置方式&#xff0c;大部分情况可以根据会签和非会签控制是否需要所有人都审批&#xff0c;例如&#xff1a; 这里选择的会签就是需要这四个人都必须审批流程&#xff0c;这个流程…

台灯哪种灯光对眼睛好?保护眼睛要选央视公认最好的护眼灯

根据最新的文献当中的近视人群的数据我们发现&#xff0c;亚洲人的近视患病率更高&#xff0c;为70-90%&#xff0c;而美国人和欧洲人的近视患病率为30-40%&#xff0c;也就是说&#xff0c;近视的发病率与种族有关。其次跟近视相关的环境因素有很多&#xff0c;主要有近距离工…

微服务架构Gin-etcd-gRPC接合的入门实践

最近在学习微服务&#xff0c;先后学习gRPC、etcd。学习过这两个技术之后&#xff0c;结合Gin框架&#xff0c;简单实现了一个微服务的小demo了。 以下是各技术在微服务架构中的功能。 Gin框架作为网关&#xff0c;外部请求的统一出口。负责将外部的HTTP请求转化为RPC请求&…

伦敦金实时行情决策辅助!

在伦敦金实时交易的过程中&#xff0c;投资者主要依赖技术分析来辅助自己的投资决策。与基本面分析不同&#xff0c;技术分析侧重于研究金价的走势和市场行为&#xff0c;通过图表和技术指标来预测未来的市场走势。常用的技术分析方法包括&#xff1a; 趋势线和支撑阻力位&…

使用AutoDL安装Mamba官方代码

使用AutoDL安装Mamba 租界的云服务器使用环境ubuntu22.04, cuda 11.8, cudnn8.9 python 3.10 torch2.10 远程连接验证安装条件 使用Pycharm连接远程的云GPU服务器 使用nvidia-smi 和 nvcc -V python conda info-e来验证云主机是否具有安装的条件。 conda创建虚拟环境并安装pyt…