手写代码(笔试面试真题)

zz/2024/6/13 22:21:49

★★★ 手写代码:实现forEach map filter reduce

★★★ 手写实现一个简易的 Vue Reactive

★★★ 手写代码,监测数组变化,并返回数组长度

★★★ 手写原生继承,并说出局限性?

★★★★ 手写一个柯里化函数

★★★ 手写一个反柯里化函数

★★★★ 手写一个Promise

★★★ 手写一个instanceOf

★★★ 手写ajax

★★★ 手写JSONP的原理和实现

★★★★ 手写深拷贝

★★★ 手写浅拷贝

★★★★ 手写 bind

★★★★ 手写 call

★★★★ 手写 apply

★★★ 手写模拟 object.create

★★★ 手写模拟 Object.is

★★★ 手写 new

★★★ 手写对象扁平化

★★★ 手写数组扁平化

★★★ 手写数组去重

★★★ 手写模拟实现 async/await

★★★★ 手写实现发布/订阅模式

★★★★ 手写防抖

★★★★ 手写节流

手写代码面试真题

★★★ 手写代码:实现forEach map filter reduce

 // 1. ------_forEach--------// Array.prototype.forEach() 方法对数组的每个元素执行一次给定的函数。//  arr.forEach(callback(currentValue [, index [, array]])[, thisArg])Array.prototype._forEach = function (fn, thisArg) {if (typeof fn !== 'function') throw '参数必须为函数'if (!Array.isArray(this)) throw '只能对数组使用此方法'let arr = thisfor (let i = 0; i < arr.length; i++) {fn.call(thisArg, arr[i], i, arr)  //用call来改变fn里面this的指向}}//test// window.value = 0// let obj = { value: 1 }// let arr = ["_", "for", "each"]// arr._forEach(//   function (ele, index, arr) {//     console.log("ele, index, arr", ele, index, arr);//     console.log("this.vaule", this.value);//   }, obj)// 2. ------_map--------// Array.prototype.map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。//  arr.map(callback(currentValue [, index [, array]])[, thisArg])Array.prototype._map = function (fn, thisArg) {if (typeof fn !== 'function') throw "参数必须是回调函数"if (!Array.isArray(this)) throw "只能为数组使用此方法"const arr = this      //将调用者(实例化的arr)赋值给arrconst newArr = []for (let i = 0, len = arr.length; i < len; i++) {newArr.push(fn.call(thisArg, arr[i], i, arr))//将每次调用的回调函数fn的返回值push到新数组中}return newArr  //返回新数组}//test// window.value = 0// let obj = { value: 1 }// let arr = ["_", "for", "each"]// const newArr = arr._map(//   function (ele, index) {//     return ele + "你好" + index//   }, obj)// console.log(newArr);// 3. ------_filter--------// Array.prototype.map() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。 //  arr.filter(callback(currentValue [, index [, array]])[, thisArg])Array.prototype._filter = function (fn, thisArg) {if (typeof fn !== 'function') throw "参数必须是回调函数"if (!Array.isArray(this)) throw "只能为数组使用此方法"const arr = this      //将调用者(实例化的arr)赋值给arrconst newArr = []for (let i = 0, len = arr.length; i < len; i++) {if (fn.call(thisArg, arr[i], i, arr)) { //判断回调的返回值是否为truenewArr.push(arr[i])}}return newArr  //返回新数组}//test// window.value = 0// let obj = { value: 1 }// let arr = ["_", "for", "each"]// const newArr = arr._filter(//   function (ele, index) {//     return ele == "for"//   }, obj)// console.log(newArr);//???????传入的数组这个参数的作用是???????// 4. ------_reduce--------// Array.prototype.map() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。//  arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])Array.prototype._reduce = function (_reducer, initialValue) {if (typeof _reducer !== 'function') throw "参数必须是回调函数"if (!Array.isArray(this)) throw "只能为数组使用此方法"if ((!this.length && !initialValue)) throw "请传入初始值或者给非空对象使用此方法"let arr = this    //将调用者(实例化的arr)赋值给arrlet result = initialValue || arr[0]  //初始值for (let i = 0, len = arr.length; i < len; i++) {if (!initialValue && i == 0) continue // 如果提供了initialValue,则起始索引号为0,否则从索引1起始。result = _reducer(result, arr[i], i, this)}return result  //返回新数组}// //test// let arr = [1, 3, 4]// const Result = arr._reduce(function (accumulator, currentValue, index, array) {//   console.log(index);//   return accumulator + currentValue// }, 2)// console.log(Result);

★★★ 手写实现一个简易的 Vue Reactive

★★★ 手写代码,监测数组变化,并返回数组长度

//手写代码,监测数组变化,并返回数组长度
// 获取Array的原型,并创建一个新的对象指向这个原型// const arrayMethods = Object.create(Array.prototype)// 创建一个新的原型,这就是改造之后的数组原型const ArrayProto = []// 重新构建Array原型里面的虽有方法Object.getOwnPropertyNames(Array.prototype).forEach(method => {if (typeof Array.prototype[method] === "function") {ArrayProto[method] = function () {console.log("我已经监听到数组触发了" + method + "事件")let len = this.lengthlet result = Array.prototype[method].apply(this, arguments)console.log(len, this.length);if (len !== this.length) return this.lengthreturn result}}})let list = [1, 2, 3]// 将数组的原型链指向新构造的原型list.__proto__ = ArrayProto// 执行push事件console.log(list.push(2), list.pop(2), list.slice(2), list.unshift(2));

★★★ 手写原生继承,并说出局限性?

★★★★ 手写一个柯里化函数

//柯里化:固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。核心思想是把多参数传入的函数拆成单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数。
//好处: 入口单一,易于测试和复用  
//缺点:  函数嵌套多、占内存function Curry(fn,...args){return (..._args)=>{return fn(...args,..._args))}
}function V(l,w,h){return l*w*h
}const hcy =Curry(V,10)
hcy(5,8)   //400
hcy(6,7)   //420

★★★ 手写一个反柯里化函数

//反柯里化,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。使本来只有特定对象才适用的方法,扩展到更多的对象。
Function.prototype.unCurrying = function() {const self = thisreturn function(...rest) {return Function.prototype.call.apply(self, rest)}
}

★★★★ 手写一个Promise

class Promise{constructor(executor){this.state = 'pending';this.value = undefined;this.reason = undefined;this.onResolvedCallbacks = [];this.onRejectedCallbacks = [];try{  // 如果executor执行报错,直接执行rejectexecutor(this.resolve, this.reject);} catch (err) {reject(err);}}//成功resolv(value){// state改变,resolve调用就会失败if (this.state === 'pending') {// resolve调用后,state转化为成功态this.state = 'fulfilled';// 储存成功的值this.value = value;}};//失败reject(reason) {// state改变,reject调用就会失败if (this.state === 'pending') {// reject调用后,state转化为失败态this.state = 'rejected';// 储存失败的原因this.reason = reason;}};//then方法then(onFulfilled,onRejected) {// 声明返回的promise2let promise2 = new Promise((resolve, reject)=>{if (this.state === 'fulfilled') {let x = onFulfilled(this.value);// resolvePromise函数,处理自己return的promise和默认的promise2的关系resolvePromise(promise2, x, resolve, reject);};if (this.state === 'rejected') {let x = onRejected(this.reason);resolvePromise(promise2, x, resolve, reject);};if (this.state === 'pending') {this.onResolvedCallbacks.push(()=>{let x = onFulfilled(this.value);resolvePromise(promise2, x, resolve, reject);})this.onRejectedCallbacks.push(()=>{let x = onRejected(this.reason);resolvePromise(promise2, x, resolve, reject);})}});// 返回promise,完成链式return promise2;}
}

★★★ 手写一个instanceOf

function instanceOf(left,right){let proto = left.__proto__let prototype = right.prototypewhile(true){if(proto === null) return falseif(proto === prototype) return true proto = proto.__proto__;}
}

★★★ 手写ajax

//1.创建对象
let  xhq = new XMLHttpRequest()
//2.初始话http请求参数
xhq.open(methode, url, true)
//3.发送请求
xhq.send({username:'wzx'
})
//4.监听请求状态,执行对应的回调函数
xhq.onreadystatechange = function () {if ( xhq.readystate == 4 && xhq.status == 200 ) {// success 回调success(xhq.responseText)}  else if (xhq.readyState == 4 && xhq.status !== 200) {// error 回调error()}
}//-----------完整实现-----------
function sendAjax(obj) {function splicStr(data) {// get方式传入时,将内容进行data内容进行拼接var str = ''for (var i in data) {str = i + '=' + data[i]}return str}// 原生ajax实现 步骤分析
// 一、声明XMLHttpRequest, 为了兼容IE5、6需要使用ActiveXObject()let xhq = new XMLHttpRequest() // 创建对象
// 二、初始化HTTP请求参数, 只初始化并不会发送if (obj.method.toUpperCase() === 'GET') { // get方法xhq.open(obj.method, obj.url + '?' + splicStr(obj.data),  typeof obj.async === 'boolean'? obj.async : true) // 路径拼接xhq.send()// 三、发送此次请求}else if (obj.method.toUpperCase() === 'POST') { // post方法xhq.open(obj.method, obj.url, typeof obj.async === 'boolean'? obj.async : true)xhq.setRequestHeader("content-type","application/x-www-form-urlencoded") // 以表单提交xhq.send(obj.data)// 三、发送此次请求}
//四、监听发送xhq.onreadystatechange = function () {if ( xhq.readyState == 4 && xhq.status == 200 ) {// success 回调success(xhq.responseText)} else if (xhq.readyState == 4 && xhq.status !== 200) {// error 回调error()}}
}sendAjax({url: 'your url',method: 'post',async: true,data: {username: 'xiong',pwd: '123'},success: function (data) {console.log(data)},error: function () {console.log('发生了错误')}
})

★★★ 手写JSONP的原理和实现

function jsonp(url,data,callback){var funcName = 'jsonp_'+Date.now()+Math.random().toString().substr(2, 5)//如果有其他参数需要拼接if(typeof data==='object'){var tmpArr = []for (let key in data){let value =data[key]tmpArr.push(key+'='+value)}data = tmpArr.join('&')}let script = document.createElement('script')script.src = url + '?' + data + '&callback= ' + funcNamedocument.body.appendChild(script)window[funcName]= function (data){callback(data)//清除标签delete Window[funcName]document.body.removeChild(script)}
}

★★★★ 手写深拷贝

//乞丐版
function deepCopy(obj){return obj.JSON.Parse(JSON.Stringify(obj))
}//面试够用版
function deepCopy(obj){if(typeof obj)if(typeof obj =='object'){//判断是否为复杂数据源类型var result = obj.constructor == Array?[]:{}  //数组还是对象for(let i in obj){result[i]= typeof obj[i] =='object'? deepCopy(obj[i]):obj[i]}}else{//简单数据类型 var result = obj;}return result
}

★★★ 手写浅拷贝

function clone(target) {if(target === null ) {return target}// 克隆 数组 和 对象let cloneTarget = Array.isArray(target) ? [] : {}for (const key in target) {if (target.hasOwnProperty(key)) {//判断是否是本身的属性cloneTarget[key] = target[key]}}return cloneTarget
}

★★★★ 手写 bind

Function.prototype.myBind = function(context) {if (typeof this !== 'function') {throw new TypeError('Error')}//返回一个绑定this的函数,这里我们需要保存thisconst _this = thisconst args = [...arguments].slice(1)//返回一个函数return function F() {//因为返回一个函数,我们可以new F()需要判断能当做构造函数吗if (this instanceof F) { //实例是F这个构造函数造出来的return new _this(...args, ...arguments)  }return _this.apply(context, args.concat(...arguments))}
}

★★★★ 手写 call

Function.prototype.myCall = function(context) {context=context||window //传入参数的话,就指定context为this指向,否则指定windowcontext.fn = thisconst args = [...arguments].slice(1) //入参删除contextconst result = context.fn(...args)delete context.fnreturn result
}

★★★★ 手写 apply

Function.prototype.myApply = function(context) {context = context || windowcontext.fn = this   //给传入的上下文对象添加一个fn方法,这个fn方法即为myApply调用者let result if(arguments[1]){result = context.fn(...arguments[1])}else{result = context.fn()}delete context.fnreturn result
}

★★★ 手写模拟 object.create

function _create (obj){function F(){}  //创建一个构造函数F.prototype = obj  //将构造函数的原型对象赋值return new F()
}

★★★ 手写模拟 Object.is

function _is(x, y) {if (x === y) {//运行到1/x === 1/y的时候x和y都为0,但是1/+0 = +Infinity, 1/-0 = -Infinity, 是不一样的return x !== 0 || y !== 0 || 1 / x === 1 / y} else {//NaN===NaN是false,这是不对的,我们在这里做一个拦截,x !== x,那么一定是 NaN, y 同理//两个都是NaN的时候返回truereturn x !== x && y !== y}
}console.log(is(+0, -0))
console.log(is(NaN, NaN))

★★★ 手写 new

//new的实现过程(实际上就是调用这个构造函数,同时将构造函数的prototype上的属性方法挂上去。)
//1. 新建一个对象
//2. 对象 继承 构造函数的 原型链
//3. 将构造函数的this指向这个对象
//4. 根据构造函数的返回值的返回结构
function myNew(fn){ let obj = {} //定义空对象objobj = Object.create(fn.prototype) //将传入的构造函数的prototype属性方法复制到obj里面let args = Array.prototype.slice.call(arguments,1)// 获取除去fn之外的参数//或者  [...arguments].slice(1)let result = fn.call(obj,...args)  // 调用传入的构造函数,矫正this为obj,并传入argsreturn typeof result === 'object'||result instanceof Function? result : obj;//如果构造函数返回引用类型,直接返回,否则返回obj
}class Foo{constructor(){this.name = 'ciel'this.arg = arguments[0]}callname(){console.log(this.name)}
}// 测试
let test = myNew(Foo, 'hhh', '123', 'saf')
test.callName()
console.log(test.arg)

★★★ 手写对象扁平化

export function jsonFlatten(data) {var result = {}function recurse(cur, prop) {if (Object(cur) !== cur) {result[prop] = cur} else if (Array.isArray(cur)) {for (var i = 0, l = cur.length; i < l; i++) { recurse(cur[i], prop + '[' + i + ']') }if (l === 0) { result[prop] = [] }} else {var isEmpty = truefor (var p in cur) {isEmpty = falserecurse(cur[p], prop ? prop + '.' + p : p)}if (isEmpty && prop) { result[prop] = {} }}}recurse(data, '')return result
}

★★★ 手写数组扁平化

//第一种 正则表达式
function flatten(arr){let str = JSON.stringify(arr);return str.replace(/(\[\]))/g,'').split(',')
}
//第二种 递归
function flatten(arr, result = []) {if (!Array.isArray(arr)) {result.push(arr)return result}for (let value of arr) {flatten(value, result)}return result
}
//第三种 数组字符串方法
function flatten(arr) {return arr.toString().split(',').map(ele => parseInt(ele))
}//第四种
function flatten(arr){while(arr.some(item => Array.isArray(item))){arr = [].concat(...arr);}return arr;
}

★★★ 手写数组去重

//1.ES6的Setfunction unique(arr){ruturn Array.from(new Set(arr))   }
//2. 双层for循环function unique(arr) {let result = []for (let i = 0, len = arr.length; i < len; i++) { //第一层遍历let flag = false  //进行标记for (let k = i + 1, len = arr.length; k < len; k++) {if (arr[i] === arr[k]) {  //如果后面有重复的就跳过flag = truek = arr.length}}if (!flag) result.push(arr[i]) //没有重复的,添加到数组中}return result}
//3. 利用数组的indexOf方法 function unique(arr) {let result = []for (let i = 0, len = arr.length; i < len; i++) {if (result.indexOf(arr[i]) === -1) result.push(arr[i])}return result}
//4. 利用类似桶排序的方法function unique(arr) {let result = []   let bucket = [];  //创建一个桶for (let i = 0, len = arr.length; i < len; i++) {bucket[arr[i]] = 1   //将有些桶标记}for (key in bucket) { //取出有标记的桶的下标console.log(key);result.push(Number(key))}return result}
//5. 利用filter方法function unique(arr) {return arr.filter((ele, index) => (arr.indexOf(ele) === index)) //过滤}//6. 利用map方法function unique(arr) {return arr.map((ele, index) => {if (arr.indexOf(ele) === index) return ele})}
//7.排序后进行数组function unique(arr) {arr.sort()let result = []arr.forEach((ele, index) => {if (ele !== arr[index + 1]) result.push(ele)})return result}

★★★ 手写模拟实现 async/await

★★★★ 手写实现发布/订阅模式

class Subject { //定义被观察者constructor() {this.observers = []}addObserver(observer) { //订阅this.observers.push(observer)}removerObserver(observer) {//取消订阅let index = this.observers.indexOf(observer)if (index !== -1) {this.observers.splice(index, 1)}}notify() {  //通知this.observers.forEach(observer => {observer.update()})}
}class Observer { // 定义观察者update() {console.log('subject更新了');}subscribeTo(subject) {subject.addObserver(this)}
}let subject = new Subject() //被观察者
let observer1 = new Observer()  //观察者
observer1.subscribeTo(subject) //观察者进行订阅
let observer2 = new Observer()  //观察者
observer2.subscribeTo(subject) //观察者进行订阅
subject.notify()

★★★★ 手写防抖

funtion debounce(fn,delay){let timer = nullreturn ()=>{clearTimeout(timer)timer =  setTimeout(()=>(fn()),delay)}
}let a = debounce(()=>(console.log('防抖处理')),500)function 点击事件(){a()
}

★★★★ 手写节流

function throttle(fn, delay = 500) {let lastTime, timereturn function(){let context = this;let args = [].slice.call(arguments);time = Date.now()if (!lastTime || time - lastTime > delay) {fn.apply(context)lastTime = time}}
}function fn(){console.log('节流')
}let a =  throttle(fn, 1000)function 点击事件(){a()
}

http://www.ngui.cc/zz/2390163.html

相关文章

2021-最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)---手写代码篇

★★★ 手写代码&#xff1a;实现forEach map filter reduce ★★★ 手写实现一个简易的 Vue Reactive ★★★ 手写代码&#xff0c;监测数组变化&#xff0c;并返回数组长度 ★★★ 手写原生继承&#xff0c;并说出局限性&#xff1f; ★★★★ 手写一个柯里化函数 ★★★…

可以设置过期时间的Java缓存Map

前言 最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式。项目前期暂时不引进redis&#xff0c;暂时用java内存代替。 解决方案 1. ExpiringMap 功能简介 &#xff1a; 1.可设置Map中的Entry在一段时间后自动过期。 2.可设置Map最大容纳值&#xff0c;当到达Maxim…

后端技术杂谈4:Elasticsearch与solr入门实践

阮一峰&#xff1a;全文搜索引擎 Elasticsearch 入门教程 阅读 1093收藏 762017-08-23原文链接&#xff1a;www.ruanyifeng.com9月7日-8日 北京&#xff0c;与 Google Twitch 等团队技术大咖面对面www.bagevent.com 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch …

第25章 JDBC核心技术第4节:操作BLOB类型字段

4.1 MySQL BLOB类型 MySQL中&#xff0c;BLOB是一个二进制大型对象&#xff0c;是一个可以存储大量数据的容器&#xff0c;它能容纳不同大小的数据。 插入BLOB类型的数据必须使用PreparedStatement&#xff0c;因为BLOB类型的数据无法使用字符串拼接写的。 MySQL的四种BLOB类…

Java学习个人总结

声明&#xff1a;个人原创&#xff0c;转载请在文章开头明显位置注明出处&#xff1a;https://www.cnblogs.com/sunshine5683/p/10063960.html 学习从来都是一个阶段的学习&#xff0c;然后进行整理与总结&#xff0c;最后才能形成自己的东西&#xff0c;今天将最近所学习的内容…

(翻译自用)TG^2———IJDAR杂志论文

TG2: 用于恢复文档可读性和感知质量的文本引导转换器GAN 摘要 大多数侧重于数字化文本文档恢复的图像增强方法仅限于文本信息仍保留在输入图像中的情况&#xff0c;而这种情况可能通常不是这样。在这项工作中&#xff0c;我们提出了一种新的生成性文档恢复方法&#xff0c;该…

基于Kubernetes/K8S构建Jenkins持续集成平台(一)

目录 Kubernetes实现Master-Slave分布式构建方案 传统Jenkins的Master-Slave方案的缺陷 KubernatesDockerJenkins持续集成架构图 KubernatesDockerJenkins持续集成方案好处 NFS简介 在Kubernetes安装Jenkins-Master 创建nfs-client-rbac 创建NFS client provisioner 创建 nfs…

中国汽水制造商市场趋势报告、技术动态创新及市场预测

汽水制造商市场的企业竞争态势 该报告涉及的主要国际市场参与者有SodaStream、Bonne、Flavorstation、Hamilton Beach、Drinkmate、iSODA、Cuisinart、Delight、Fizz Giz、Frostte、Jaybrake、KitchenAid、KOBWA、Leegoal、Lourdes、Lucky Sports、New、Primo Flavorstation、S…

mysql日志备份命令是什么_mysql的常用命令以及备份和恢复

首先建立一个计划并严格遵守&#xff0c;定期实施备份。让服务器执行更新日志。当你在崩溃后需要恢复数据时&#xff0c;更新日志将帮助你。在你用备份文件恢复数据到备份时的状态后&#xff0c;你可以通过运行更新日志中的查询再次运用备份后面的修改&#xff0c;这将数据库中…

数据结构线性表(1)

顺序表C语言代码实现 实验要求&#xff1a;编写一个头文件SqList.h&#xff0c;实现顺序表的各种基本操作&#xff0c;并在此基础上设计一个主程序&#xff08;exp2_1.cpp&#xff09;完成如下功能&#xff1a; &#xff08;1&#xff09; 初始化顺序表L &#xff08;2&#xf…