面试题手撕篇

参考博客

开始之前,理解递归

在这里插入图片描述

手写 浅拷贝

function shallow(target){if(target instanceof Array){return [...resObj]}else{return Object.assign({},target);}
}

手写深拷贝

const _sampleDeepClone = target => {// 补全代码return JSON.parse(JSON.stringify(target))}

无法处理处理循环引用的问题

完整写法

function DeepCopy(target, map = new Map()) {//对于普通类型 直接返回即可if(typeof target!=='object' || target===null){return target}//主要处理的是引用类型let result = Array.isArray(target)?[]:{};if (map.has(target)) {result = map.get(target);} else {map.set(target, result);for (let key in target) {if (target.hasOwnProperty(key)) {if (typeof target[key] === "object") {result[key] = DeepCopy(target[key], map);} else {result[key] = target[key];}}}}return result;
}

手写new

当你使用 new Person() 来调用构造函数 Person 时,它会创建一个新的对象,并将该对象的原型设置为 Person.prototype。这个新对象可以通过 this 关键字在构造函数内部访问和设置属性。

在这里插入图片描述
在这里插入图片描述

function Person(name, age){this.name=name;this.age=age;return{abc:'abc'} //mynew中最后的判断就是为了防止这种情况:构造函数会返回值,而不会创建新的实例
}function myNew(func, ...args) {//接受不确定长度的参数放到args数组中if (typeof func !== "function") {return new TypeError("fn must be a function");}//把新对象的__proto__指向func.prototypelet obj = Object.create(func.prototype);//构造函数内部的 this 值指向新创建的对象,从而在构造函数中正确地初始化新对象的属性和方法。//apply会立即执行//result接受执行结果let result = func.apply(obj, args);//如果构造函数有返回值,则返回这个返回值,没有的话返回新创建的对象if (result && (typeof result === "object" || typeof result === "function")) {return result;} else {return obj;}
}// const f1=new Person("xiaoming",22)
const f2= myNew(Person,"xiaoming",22)
console.log(f2);

手写instanceof

在这里插入图片描述

function myInstanceof(obj,target){
//obj是被判断的对象
//target是一个构造函数if(typeof obj!=='object'|| typeof target !== 'function'){return new TypeError("inputs must be object type!")}let objProto = obj.__proto__while(objProto!==null){//注意这里用的是 构造函数.prototypeif(objProto===target.prototype) return trueobjProto = obj.__proto__}return false
}
console.log(myInstanceof([1,2],Array));

Object.create

Object.create(proto)返回一个新对象,新对象的原型是proto

【可以不看】proto应该填入一个对象,而不是一个构造函数。
如果你使用 Object.create(Person),而不是 Object.create(Person.prototype)
person 对象的原型将直接设置为 Person 构造函数本身,而不是 Person 构造函数的原型。这意味着 person 对象将无法继承 Person.prototype 上的属性和方法。
这意味着 person 对象将继承 Function.prototype 上的属性和方法,而不是 Person.prototype 上的属性和方法。

在这里插入图片描述


function myOBJcreate(proto){function f(){}f.prototype = protoreturn new f()
}const obj1={name:'alice',age:11
}
const f1 = Object.create(obj1)
const f2 = myOBJcreate(obj1)
//不需要比较,因为f1 f2是两个不同的对象

手写 防抖

主要思路:定时器控制1s后触发,并且保证只有一个定时器会被触发(timer的作用)
其实就是用定时器,来控制,这个函数只能1s后触发。

    let Inp = document.querySelector("input");function getValue() {console.log(`获取${Inp.value}`);}Inp.addEventListener("keyup", debounce(getValue, 1000));//业务代码function debounce(func, time) {let timer = null;return function () {if (!timer) {timer = setTimeout(() => {func.apply(this, arguments);timer = null;}, time);}};}

如果你想传参:

    let Inp = document.querySelector("input");function getValue(name) {console.log(`${name}获取${Inp.value}`);}newfunc = debounce(getValue, 1000);Inp.addEventListener("keyup", ()=>{newfunc("xiaoming")});function debounce(func, time) {let timer = null;return function () {if (!timer) {timer = setTimeout(() => {func.apply(this, arguments);timer = null;}, time);}};}

节流防抖巧记!

下面是业务代码,只有一行不同。
可以先把防抖的写出来(防抖的更容易理解),然后吧func.apply移出timer即可。
即节流第一次触发就要执行。

    function debounce(func, delay) {let timer = null;return function () {if (!timer) {timer = setTimeout(() => {func.apply(this, arguments);timer = null;}, delay);}};}const throttle = (func, delay) => {let timer;return function () {if (!timer) {func.apply(this, arguments);timer = setTimeout(() => {timer = null;}, delay);}};};

手写 节流(另一种方式,了解)

主要思路:判断上次触发的时间和这次的时间
使用方法是这样的:

const throttledFunction = throttle(myFunction, 1000); // 设置节流时间为1秒

throttledFunction就是一个具有节流功能的函数。你可以调用它来代替原始的myFunction函数。

const throttle = (func, delay) => {let timer;return function () {if (!timer) {func.apply(this, arguments);timer = setTimeout(() => {timer = null;}, delay);}};
};function test(name){this.name = name;console.log(`name is ${name}`);
}let newfunc = throttle(test,5000)newfunc('xiaoming') //只会运行1个
newfunc('xiaoming')

手写call

函数科里化的实现

前置:reduce方法:arr.reduce((accumulator, currentValue, currentIndex, array)=>{},初始值)

实现add函数:
在这里插入图片描述

function add(...args){const sum = args.reduce((total,num)=>total+num,0);//用curry判断还有没有剩余参数function curry(...nextArgs){//闭包,递归的终止条件//如果没有剩余参数,输出结果if(nextArgs.length===0){return sum;}//如果有,则继续加return add(sum,...nextArgs);}return curry;
}console.log(add(1)(2)(3)()); // 输出: 6
console.log(add(1, 2, 3)(4)()); // 输出: 10
console.log(add(1)(2)(3)(4)(5)()); // 输出: 15

promise.all

要点:

  • promise里面不需要return,而是需要resolve和reject
  • 如果在Promise.all中的Promise数组中有一个或多个Promise被拒绝(即失败),Promise.all返回的新的Promise会立即被拒绝,并且会传递第一个被拒绝的Promise的错误原因。

思路:for循环遍历所有的promises数组,所有的都成功则resolve,有一个失败则立即reject

function myPromiseAll(promises) {return new Promise((resolve, reject) => {if (!Array.isArray(promises)) {reject(new TypeError("参数必须是一个数组"));}let results = [];if (promises.length === 0) {resolve(results);}for (let promise of promises) {promise.then((res) => {results[results.length] = res;if (results.length === promises.length) {return resolve(results);}}).catch((error) => {reject(error);});}});
}

Promise.race

要点:
如果在 Promise.race 中的第一个 Promise 对象被拒绝(rejected),则整个 Promise.race 会立即拒绝(reject)并返回该拒绝的原因。后续的 Promise 对象不会再被执行。

function myPromiseRace(promises) {return new Promise((resolve, reject) => {if (!Array.isArray(promises)) {reject(new TypeError("argus must be a array"));}for (let promise of promises) {promise.then((result) => {resolve(result);}).catch((error) => {reject(error);});}});
}

数组扁平化

方法1:展开数组,层层剥开【推荐】

let arr = [1, [2, [3, 4, 5]]]function flatten2(arr){while(arr.some((item)=>Array.isArray(item))){arr = [].concat(...arr)}return arr;
}console.log(flatten2(arr));

方法2:判断当前项是否为数组 如果是数组递归调用 不是就push到新数组

function flatten(arr) {let newArr=[];for(let item of arr){if(Array.isArray(item)){newArr = newArr.concat(flatten(item))}else{newArr.push(item)}}return newArr;
}

数组去重

两种方法

function only1(arr){return arr.filter((value,index)=>{return arr.indexOf(value)===index})
}

其中,indexOf 方法会返回指定元素在数组中第一次出现的索引

function only(arr){return [...new Set(arr)]
}

实现reduce

array.reduce(callbackfn: (previousValue,currentValue, currentIndex, array), initialValue )

Array.prototype.myReduce = function(callback, initialValue){//判断参数是否正确if(typeof callback !=='function'){return new TypeError("callback must be a function")}let accumulator;//检查有没有设置初始值if(!initialValue){if(this.length===0){return new TypeError("can't reduce a empty array")}accumulator = this[0]}else{accumulator = initialValue}//循环调用callbackfor(let i = initialValue?0:1;i<this.length;i++){accumulator = callback(accumulator,this[i],i,this)}//返回结果值return accumulator;
}
console.log([1,2,3].myReduce((pre,cur)=>{return pre+cur},0));

实现push

Array.prototype.myPush = function(){for(let i=0;i<arguments.length;i++){this[this.length]=arguments[i]}return this.length;
}

数组转树

测试数据:

let source = [{id: 1,pid: 0,name: 'body',},{id: 2,pid: 1,name: 'title',},{id: 3,pid: 2,name: 'div',},{id: 4,pid: 0,name: 'html',},{id: 5,pid: 4,name: 'div',},{id: 6,pid: 5,name: 'span',},{id: 7,pid: 5,name: 'img',},
][// 转为({id: 1,pid: 0,name: 'body',children: [{id: 2,pid: 1,name: 'title',children: [{ id: 3, pid: 2, name: 'div' }],},],},{id: 4,pid: 0,name: 'html',children: [{id: 5,pid: 4,name: 'div',children: [{ id: 7, pid: 5, name: 'img' }],},],})
]

普通版本:

    function buildTree(arr, parentId) {let result = [];for (const item of arr) {if (item.pid === parentId) {item.children = buildTree(arr, item.id);result.push(item);}}return result;}

可以防止循环引用的版本:

    function buildTree(arr, pid = 0) {const nodeMap = new Map();const result = [];arr.forEach((item) => nodeMap.set(item.id, { ...item, children: [] }));for (const item of arr) {if (item.pid === pid) {const children = buildTree(arr, item.id);nodeMap.get(item.id).children = children;result.push(nodeMap.get(item.id));}}return result;}

树转数组

function TreeToArray(arr){let result = []for(let item of arr){if(item.children){result = result.concat(TreeToArray(item.children))delete item.childrenresult.push(item)}else{result.push(item)}              }return result;
}

斐波那契数列的迭代和递归实现

    function fiber(n) {if (n >= 0) {if (n == 0) return 0;if (n == 1) return 1;return fiber(n - 1) + fiber(n - 2);}}function fiber2(n){let F=[]F[0]=0;F[1]=1;for(let i=2;i<=n;i++){F[i]=F[i-1]+F[i-2]}console.log(F);return F[n]}

实现每隔一秒打印 1,2,3,4

注意那个时间一定要写对!!1000*i

    for(let i=1;i<5;i++){setTimeout(()=>{console.log(i)},1000*i)}

使用 setTimeout 实现 setInterval

视频bilibili
这个问题的背景:
setInterval有时会失效,比如下面这个例子:
在这里插入图片描述
这样的话,每次调用这个回调之间的间隔就会超过1s,因为后面一个回调需要等待前面一个回调完成。

运行:
在这里插入图片描述
正常情况下:
在这里插入图片描述
不正常情况下:
在这里插入图片描述


//基础版

    function newInterval(fn, delay) {function inside(){fn()setTimeout(inside,delay);}inside();}

上面的代码有个缺点就是第一个 inside();执行的fn不会被放入任务队列,而是放入了执行栈,这与setinerval的行为不符,为了更加模拟,可以这样修改:

function newInterval(func, delay){function inside(){func()setTimeout(inside,delay)}setTimeout(inside,delay);
}

完整版:加上取消定时器的功能:

function newInterval(func,delay){
let timer;function inside(){func();timer = setTimeout(inside,delay)}timer = setTimeout(inside,delay)return{cancel:function(){clearTimeout(timer);	}}
}

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

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

相关文章

EtherCAT开源主站 IGH 介绍及主站伺服控制过程

目录 前言 IGH EtherCAT主站介绍 主要特点和功能 使用场景 SOEM 主站介绍 SOEM 的特点和功能 SOEM 的使用场景 IGH 主站 和 SOEM对比 1. 功能和复杂性 2. 资源消耗和移植性 3. 使用场景 EtherCAT 通信原理 EtherCAT主站控制伺服过程 位置规划模式 原点复归模式…

Ansible非标记语言YAML与任务剧本Playbook

前言 上篇介绍了 Ansible 单模块&#xff08;AD-Hoc&#xff09;的相关内容Ansible自动化运维Inventory与Ad-Hoc-CSDN博客&#xff0c;Ad-Hoc 命令是一次性的、即时执行的命令&#xff0c;用于在远程主机上执行特定任务&#xff0c;这些命令通常用于快速执行简单的任务。当需要…

MS08-067 漏洞利用与安全加固

文章目录 环境说明1 MS08_067 简介2 MS08_067 复现过程3 MS08_067 安全加固 环境说明 渗透机操作系统&#xff1a;2024.1漏洞复现操作系统: Windows XP Professional with Service Pack 2- VL (English)安全加固复现操作系统&#xff1a;Windows XP Professional with Service …

C语言案例2,请编程序将“China“译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母,变为Glmre,持续更新~

一.题目 /* 请编程序将“China”译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。 例如,字母“A”后面第4个字母是“E”&#xff0c;用“E”代替“A”。因此,“China”应译为“Glmre”。 请编一程序,用赋初值的方法使cl,c2&#xff0c;c3,c4,c5 这5个变量的值分…

YoloV5改进策略:下采样改进|HWD改进下采样

摘要 本文使用HWD改进下采样&#xff0c;在YoloV5的测试中实现涨点。 论文解读 在卷积神经网络&#xff08;CNNs&#xff09;中&#xff0c;极大池化或跨行卷积等下采样操作被广泛用于聚合局部特征、扩大感受野和最小化计算开销。然而&#xff0c;对于语义分割任务&#xff…

HTML_CSS练习:HTML注释

一、代码示例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>HTML注释</title> </head> <body><marquee loop"1">马龙强<!--下面的输入框是可以滚动的&#x…

【Python】清理conda缓存的常用命令

最近发现磁盘空间不足&#xff0c;很大一部分都被anaconda占据了&#xff0c;下面是一些清除conda缓存的命令 清理所有环境的Anaconda包缓存 删除所有未使用的包以及缓存的索引和临时文件 conda clean --all清理某一特定环境的Anaconda包缓存 conda clean --all -n 环境名清…

【ansible】ansible的介绍和安装

前言运维自动化 云计算核心职能 搭建平台架构 日常运营保障 性能效率优化 相关工具 代码管理&#xff08;SCM&#xff09;&#xff1a;GitHub、GitLab、BitBucket、SubVersion 构建工具&#xff1a;maven、Ant、Gradle 自动部署&#xff1a;Capistrano、CodeDeploy 持续…

字符串函数(C语言详解)

1.字符串简介 字符串是一串连续的且以\0结尾的字符 char arr[]"zhangsan";//将字符串存到数组里面 char*a"lisi";//常量字符串 char arr1[]{z,h,a,n,g};//字符数组 注意&#xff1a; 1.以第一种形式初始化字符串时&#xff0c;计算机会自动在字符串末尾加…

GraspNet-baseline复现----Linux-Ubuntu

1.基本环境 Ubuntu 20.04Cuda 11.0 、cuDNN 80.0Python 3.7.16PyTorch 1.7.0 2.环境配置 PyTorch的版本对Cuda和Python的版本都有依赖&#xff0c;所以基本步骤是 确定需要安装的PyTorch版本 —> 通过 网站 确定对应的cuda版本和python版本 —> 创建虚拟环境配置环境。…

Node.js基础+原型链污染

Node.js基础 概述&#xff1a;简单来说Node.js就是运行在服务端的JavaScript&#xff0c;Node.js是一个基于Chrome JavaScript运行时建立的一个平台 大小写变换&#xff1a; toUpperCase&#xff08;&#xff09;&#xff1a;将小写字母转为大写字母&#xff0c;如果是其他字…

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

使用FFmpeg源码配置程序configure查看所有支持的编码器/解码器/封装/解封装及网络协议

查看支持编码器: configure --list-encoders 查看支持编码器: configure --list-decoders 查看所有支持的封装: configure --list-muxers 查看所有支持的解封装: configure --list-demuxers 查看所有支持的网络通信协议: configure --list-protocols

解决jsp request.getParameter乱码问题(兼容Tomcat 6~8三个版本)

JSP页面写法&#xff1a; <% page contentType"text/html; charsetutf-8" language"java" %> <% page import"java.io.*" %> <%! int getServerVersion(HttpServletRequest request) {ServletContext application request.getS…

移远通信亮相AWE 2024,以科技力量推动智能家居产业加速发展

科技的飞速发展&#xff0c;为我们的生活带来了诸多便利&#xff0c;从传统的家电产品到智能化的家居设备&#xff0c;我们的居家生活正朝着更智能、更便捷的方向变革。 3月14日&#xff0c;中国家电及消费电子博览会&#xff08;Appliance&electronics World Expo&#xf…

【物联网】Modbus 协议及Qinghub物联网平台应用

Modbus 协议简介 QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集&#xff0c;这里就我们的实际项目经验分享Modbus协议 你可以通过QingHub作业直接体验试用&#xff0c;也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。 …

sqllab第十九关通关笔记

知识点&#xff1a; 错误注入 最大长度为32位&#xff1b;如果目标长度>32时&#xff0c;需要利用截取函数进行分段读取referer注入 insert语句update语句 通过admin admin进行登录发现页面打印除了referer字段的信息 这应该是一个referer注入 首先进行测试一下 构造payl…

基于SpringBoot和Echarts的全国地震可视化分析实战

目录 前言 一、后台数据服务设计 1、数据库查询 2、模型层对象设计 3、业务层和控制层设计 二、Echarts前端配置 1、地图的展示 2、次数排名统计 三、最终结果展示 1、地图展示 2、图表展示 总结 前言 在之前的博客中基于SpringBoot和PotsGIS的各省地震震发可视化分…

C++提高笔记(四)---STL容器(stack、queue、list)

1、stack容器&#xff08;栈&#xff09; 1.1 栈stack基本概念 概念&#xff1a;stack是一种先进后出&#xff08;First In Last Out&#xff0c;FILO&#xff09;的数据结构&#xff0c;它只有一个出口 栈中只有顶端的元素才可以被外界调用&#xff0c;因此栈不允许有遍历行…

使用C#的winform控制数据库实例服务的运行状态

一、得到sqlserver的实例名 二、引用对应的程序集和命名空间 using System.ServiceProcess; C#操作服务要用的类 ServiceController 声明类 private ServiceController serviceController new ServiceController("MSSQLSERVER"); 三、判断服务状态 serviceCon…