面试题手撕篇

参考博客

开始之前,理解递归

在这里插入图片描述

手写 浅拷贝

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主站控制伺服过程 位置规划模式 原点复归模式…

八股文打卡day32——数据库(9)

面试题&#xff1a;MySQL日志文件有哪几种&#xff1f; 我的回答&#xff1a; 1.undo log&#xff0c;撤销日志&#xff0c;是InnoDB存储引擎层面生成的日志&#xff0c;主要用于数据库事务的回滚和MVCC&#xff08;多版本并发控制&#xff09;。可以帮助数据库回滚到事务开启…

Flinkcdc通过catalog同步mysql数据到hologres的ods中

Flinkcdc通过catalog同步mysql数据到hologres的ods中大致分为以下几步: 配置Flink CDC 的MySQL catalog:CREATE CATALOG mysqlsource WITH (type = mysql,hostname = xxxx,port = xxxx,username = xxxx<

AcWing 4964.子矩阵

首先就是运用了暴力的思路&#xff0c;能够过个70%的数据&#xff0c;剩下的直接时间超时了&#xff0c;没办法优化了。 讲一下暴力的思路&#xff1a; 其实就是模拟而已&#xff0c;也就是看作想要找的矩阵为一个小窗口&#xff0c;然后不断移动的事而已。 #include<ios…

服务器远程端口故障应该如何解决并且避免

在信息化快速发展的今天&#xff0c;服务器作为支撑各类业务运行的核心设备&#xff0c;其稳定性对于企业的运营至关重要。然而&#xff0c;即使是最高端的服务器也难免会出现问题&#xff0c;其中“服务器远程端口故障”就是一个相对常见但又十分棘手的问题。德迅云安全今天就…

云计算 3月15号(linux的权限管理 进程管理 管道重定向 磁盘管理 文件查找 软件管理 计划任务 web服务器 配置文件)

一、走进Linux 服务器类型&#xff1a;塔式服务器、刀片式服务器、机架式服务器 服务器基建&#xff1a;云服务器、物理服务器、虚拟服务器、容器 操作系统&#xff1a;centos、ubuntu、debain、欧拉、龙蜥、银河麒麟、中标麒麟 # 修改时区 timedatectl set-timezone Asia/Shan…

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 持续…

生产环境中间件服务集群搭建-zk-activeMQ-kafka-reids-nacos

环境&#xff1a; 系统&#xff1a;centos7.9 工作目录&#xff1a;/home 安装包位置&#xff1a;/home/op/tools 1.系统初始化 安装依赖环境 yum -y install net-tools vim screen telnet vim gcc gcc-c 修改主机名&#xff0c;为另外两台添加hosts文件 [rootmq01 conf…

开源数据库 OpenGauss 的 SQL 解析源码分析

开源数据库 OpenGauss 的 SQL 解析源码分析 openGauss 数据库体系概述 openGauss 是关系型数据库&#xff0c;采用客户端/服务器&#xff0c;单进程多线程架构&#xff1b;支持单机和一主多备部署方式&#xff0c;同时支持备机可读、双机高可用等特性。 从代码结构体系结构的…

字符串函数(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;如果是其他字…

Docker——问题解决:服务器端和Windows端IP互通

踩了大坑&#xff0c;特此记录&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 我在服务器端部署了服务&#xff0c;但是在本地端Windows机器上无法访问&#xff0c;因此卡了一天。 1. 双向Ping通 防火墙导致只能单向Ping通 首先需要解决双向ping通的问题&…

构建部署_docker-compose常用命令

构建部署_docker-compose常用命令 前言简介docker-compose 常用命令docker-compose安装编写配置文件docker-compose.yml文件生成镜像容器 前言 使用一个Dockerfile模板文件可以定义一个单独的应用容器&#xff0c;如果需要定义多个容器就需要服务编排。下面介绍Docker官方产品…