2021前端高频面试题整理,附答案
大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信?ruochuan12
若川視野原意是若川的前端視野。但太長了就留下了四個字,不知道的以為關(guān)注的不是技術(shù)公眾號。
今天分享一篇慕課網(wǎng)精英講師河畔一角的好文章~
廢話不多說,上貨!
手寫Promise
這道題說實話已經(jīng)老掉牙了,但是還是有不少公司會問,而且還有相當(dāng)一部分前端寫不出來
function?Promise(callback){const?pending?=?'pending';const?fulfilled?=?'fulfilled';const?rejected?=?'rejected';//?當(dāng)前狀態(tài)this.state?=?pending;//?當(dāng)前值this.value?=?null;//?失敗原因this.reason?=?null;//?成功和失敗數(shù)組對象this.fulfilledCallback?=?[];this.rejectedCallback?=?[];//?成功處理this.resolve?=?(data)=>{setTimeout(()=>{if(this.state?==?pending){this.state?=?fulfilled;this.value?=?data;this.fulfilledCallback.map(fn=>fn(this.value));}})}//?失敗處理this.reject?=?(reason)=>{setTimeout(()=>{if(this.state?==?pending){this.state?=?rejected;this.reason?=?reason;this.rejectedCallback.map(fn=>fn(this.reason));}})}//?捕獲成功和失敗,扔到成功和失敗數(shù)組this.then?=?function(succesFn,errorFn){this.fulfilledCallback.push(succesFn);this.rejectedCallback.push(errorFn);}//?捕獲異常,直接扔到異常數(shù)組中this.catch?=?(errorFn)=>{this.rejectedCallback.push(errorFn);}//?默認(rèn)需要執(zhí)行一次resolve和rejectcallback(this.resolve,this.reject); }//?驗證結(jié)果 new?Promise((resolve,reject)=>{setTimeout(()=>{resolve(10);},1000) }).then((data)=>{console.log(data); },(error)=>{console.log(error); })注意事項:
Promise要暴露then/catch方法
Promise構(gòu)造函數(shù)接收一個立即執(zhí)行的函數(shù)callback
then/catch只負(fù)責(zé)把回調(diào)放入數(shù)組即可
resolve/reject負(fù)責(zé)執(zhí)行
resolve/reject 需要添加宏任務(wù)(setTimeout)
compose組合函數(shù)實現(xiàn)
后一個函數(shù)作為前一個函數(shù)的參數(shù)
最后一個函數(shù)可以接受多個參數(shù),前面的函數(shù)只能接受單個參數(shù);后一個的返回值傳給前一個
注意事項:
compose是一個聚合函數(shù)
compose執(zhí)行后返回一個函數(shù)(所以這就是為什么當(dāng)func.length==0的時候,要return一個箭頭函數(shù))
reduce始終返回一個箭頭函數(shù),后一個函數(shù)先執(zhí)行并把結(jié)果作為前一個函數(shù)的參數(shù),依次進(jìn)行
數(shù)組柯里化Curry(求和)
阿里面試題
實現(xiàn)如下效果: sum(1,3).sumOf()??4 sum(1,3)(2,4).sumOf()?10function?sum(){var?arr?=?[].slice.apply(arguments);var?fn?=?function(){arr?=?arr.concat([].slice.apply(arguments))return?fn;}fn.sumOf?=?function(){return??arr.reduce((total,num)=>total+num,0);}return?fn; }實現(xiàn)一個LazyPig
阿里面試題
實現(xiàn)一個LazyPig,可以按照以下方式調(diào)用:
LazyPig("Peggy")? //?輸出: >?Hello,I'm Peggy! LazyPig("Peggy").sleep(10).eat("dinner") //?輸出 >?Hello,I'm Peggy! //等待10秒.. Wake?up?after?10 Eat?dinner~function?LazyPig(name){console.log(`Hello,I'm?${name}`)var?fn?=?{}fn.sleep?=?function(time){console.log(`Wake?up?${time}`)let?start?=?Date.now()while(Date.now()-start<=time){}console.log(`Wake?up?down`)return?fn;}fn.eat?=?function(food){console.log(`Eat?${food}`)return?fn;}return?fn; }數(shù)組扁平化
let?list?=?[1,?5,?[9,?8],?[2,?[1,?9]],?7]; //?第一種方法: console.log(list.toString().split(','));//?第二種方法: function?flatten(list)?{return?list.reduce((prev,?item)?=>?{return?prev.concat(Array.isArray(item)???flatten(item)?:?item);},?[]) } console.log(flatten(list));對象扁平化
/** *?對象扁平化 *?說明:請實現(xiàn) flatten(input)?函數(shù),input 為一個 javascript 對象(Object 或者 Array),返回值為扁平化后的結(jié)果。 *?示例: *?var?input?=?{ *?a:?1, *?b:?[?1,?2,?{?c:?true?},?[?3?]?], *?d:?{?e:?2,?f:?3?}, *?g:?null, *?} *?var?output?=?flatten(input); *?output如下 *?{ *?"a":?1, *?"b[0]":?1, *?"b[1]":?2, *?"b[2].c":?true, *?"b[3][0]":?3, *?"d.e":?2, *?"d.f":?3, *?//?"g":?null,?值為null或者undefined,丟棄 *?} */ 解答: ```js let?result?=?{}; var?flatten?=?(data,?key)?=>?{if?(data?instanceof?Array)?{data.forEach((param,?index)?=>?{if?(param?instanceof?Object)?{flatten(param,?`${key}[${index}]`);}?else?{result[`${key}[${index}]`]?=?param;}});}?else?if?(data?instanceof?Object)?{for?(var?itemKey?in?data)?{const?itemValue?=?data[itemKey];if?(itemValue?instanceof?Object)?{flatten(itemValue,?itemKey);}?else?if?(itemValue)?{if?(key)?{result[`${key}.${itemKey}`]?=?flatten(itemValue,?itemKey);}?else?{result[itemKey]?=?itemValue;}}}}?else?{return?data;} }; flatten(input); console.log(result)數(shù)組轉(zhuǎn)換為Tree
//?數(shù)組轉(zhuǎn)換成Tree var?list?=?[{id:?1,?name:?'jack',?pid:?0},{id:?2,?name:?'jack',?pid:?1},{id:?3,?name:?'jack',?pid:?1},{id:?4,?name:?'jack',?pid:?2}, ]????const?getTree?=?(root,?result,?pid)?=>?{for?(let?i?=?0;?i?<?root.length;?i++)?{if?(root[i].pid?==?pid)?{let?item?=?{?...root[i],?children:?[]?}result.push(item)getTree(root,?item.children,?item.id)}} }let?array?=?[]; getTree(list,?array,?0) console.log(JSON.stringify(array))對象深拷貝
//?對象深度克隆 let?obj?=?{name:?'jack',age:?10,fn:?()?=>?{return?this.name;},list:?['fe',?'node',?'small'],all:?{child:?true} } //?方法一:(面試官不想要) JSON.parse(JSON.stringify(obj)) //?方法二: function?deepClone(obj){let?result;if(typeof?obj?===?'object'){result?=?Array.isArray(obj)???[]?:?{}for(let?i?in?obj){result[i]?=?typeof?obj[i]?===?'object'???deepClone(obj[i]):obj[i];}}else{result?=?obj;}return?result; }貪心算法(找零)
商店老板有1、2、5、10面額的紙幣,小伙買東西給了100花了80,計算如何找零是最佳(阿里面試題)
function?MinCoinChange(coins)?{return?function(amount)?{let?total?=?0,?change?=?[]for(let?i=?coins.length;?i>=0;?i--)?{let?coin?=?coins[i]while(total?+?coin?<=?amount)?{change.push(coin)total?+=?coin}}return?change} }MinCoinChange([1,2,5,10])(20)返回:10,10數(shù)組去重(兩次以上去重)
常規(guī)去重大家都知道Set
//?已知數(shù)組 var?arr?=?[1,1,1,1,1,1,1,3,3,3,3,3,5,5]; //?方法一 function?delRepeat(){arr?=?arr.sort();//先排序for(let?i=0;i<arr.length;i++){if(arr[i]?==?arr[i+2]){arr.splice(i,1);i--;}}return?arr; } //?方法二 function?delRepeat(){var?newArr?=?[];var?obj?=?{};arr.map(item=>{if(obj[item]){obj[item]?+=1?;}else{obj[item]?=?1;}obj[item]<=2?newArr.push(item):''})return?newArr; }大數(shù)相加算法
大數(shù)相加有很多考題形式,有整數(shù)、小數(shù)、平方根等(騰訊考題)
已知:let a = "12345.12123",b="987654.92";
function?sum(a,b){let?arr1?=?a.split(''),arr2?=?b.split('');let?count?=?0;let?arr?=?[];let?a1?=?a.split('.')[1],b1?=?b.split('.')[1];let?len?=?a1.length?-?b1.length;if(len>0)arr2.push(’0’.repeat(len))if(len<0)arr1.push(’0’.repeat(Math.abs(len)))while(arr1.length?||?arr2.length){let?m?=?arr1.pop()?||?0,n?=?arr2.pop()?||?0;if(m?!=?'.'){let?num?=?Number(m)?+?Number(n)?+?count;if(num?>?9){count?=?1;num%=10;}else{count?=?0;}?arr.unshift(num);}else{arr.unshift('.');}}if(count>0)arr.unshift(count);let?res?=?arr.join('');console.log(res); }如果是正整數(shù),BigInt會更方便處理
二叉樹求和
var?treenode?=?{value:?1,left:?{value:?2,left:?{value:?4,},right:?{value:?5,left:?{value:?7,},right:?{value:?8,},},},right:?{value:?3,right:?{value:?6,},}, }function?sum(root)?{let?list?=?[]if?(root)?list.push(root.value);if?(root.left)?{list?=?list.concat(sum(root.left));}if?(root.right)?{list?=?list.concat(sum(root.right));}return?list; } console.log(sum(treenode));爬樓梯
/* 假設(shè)你正在爬樓梯。需要 n 階你才能到達(dá)樓頂。 每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢? 思路: f(1)?:?1 f(2)?:?11?,?2 f(3)?:?12,?111,?21 f(4)?:?121,?1111,?211,?112,?22 f(n)?=?f(n-1)?+?f(n-2) */ function?fn(n)?{if?(n?==?1)?return?1;if?(n?==?2)?return?2;return?fn(n?-?1)?+?fn(n?-?2); } console.log(fn(4))簡易模板引擎
const?template?=?'嗨,{{?info.name.value?}}您好,今天是星期?{{?day.value?}}';const?data?=?{info:?{name:?{value:?'張三'}},day:?{value:?'三'} };function?render(template,?data)?{return?template.replace(/{{\s+?([\w.]+)\s+?}}/g,?function?($0,?$1)?{return?eval(`data.${$1}`)}) }const?result?=?render(template,?data);? //?嗨,張三您好,今天是星期三 console.log(result)前端模擬并發(fā)請求
已知當(dāng)前有100個請求,每次只能同時調(diào)用5個,設(shè)計一個并發(fā)函數(shù)。
function?send(){//?初始化數(shù)組let?list?=?Array.from({length:100}).map((k,i)=>i)//?最大并發(fā)次數(shù)const?limit?=?5;//定義異步函數(shù)const?asyncGet?=async?(item)=>{return?item;}//?初始化100個異步請求函數(shù),當(dāng)閉包被執(zhí)行的時候會執(zhí)行一個請求,當(dāng)請求執(zhí)行完后,會獲取下一個并執(zhí)行const?arr?=?[]const?handlers?=?()=>{list?=?list.map(item=>{return?()=>{return?asyncGet(item).then((res)=>{console.log('res:'+res)let?next?=?list.shift();if(next){next()}else{console.log('全部執(zhí)行完成')}})}})}handlers();//?一次性取出最大并發(fā)數(shù)并執(zhí)行for(let?i=0;i<limit;i++){let?fn?=?list.shift();arr.push(fn())}Promise.all(arr).then((res)=>{}) }send();防抖和節(jié)流(最經(jīng)典的閉包案例)
/* 防抖: 定義:規(guī)定時間內(nèi),只觸發(fā)一次,如果規(guī)定時間內(nèi)再次調(diào)用,會清空繼續(xù)創(chuàng)建新的任務(wù)。 場景:widow.onresize或者onscroll,或者搜索框 */ function?debounce(fn,?wait)?{var?timeout?=?null;return?function()?{if(timeout?!==?null){clearTimeout(timeout);timeout?=?setTimeout(fn,?wait);}else{timeout?=?setTimeout(fn,?wait);}} } window.addEventListener('scroll',?debounce(()=>{ //?TO-DO },?500)); /* 節(jié)流:固定時間內(nèi),只觸發(fā)一次。 場景:搜索框 */ function?throttle(fn,delay){let?valid?=?truereturn?function()?{if(!valid){//休息時間?暫不接客return?false?}//?工作時間,執(zhí)行函數(shù)并且在間隔期內(nèi)把狀態(tài)位設(shè)為無效valid?=?falsesetTimeout(()?=>?{fn()valid?=?true;},?delay)} }以上就是本次給大家整理分享的前端算法面試題,絕不是從網(wǎng)上隨意找的,很多都是我經(jīng)歷過的以及朋友面試的,希望對大家有幫助。
最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進(jìn)群。
推薦閱讀
1個月,200+人,一起讀了4周源碼
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀
老姚淺談:怎么學(xué)JavaScript?
我在阿里招前端,該怎么幫你(可進(jìn)面試群)
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列
從2014年起,每年都會寫一篇年度總結(jié),已經(jīng)寫了7篇,點擊查看年度總結(jié)。
同時,最近組織了源碼共讀活動
識別上方二維碼加我微信、拉你進(jìn)源碼共讀群
今日話題
略。歡迎分享、收藏、點贊、在看我的公眾號文章~
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的2021前端高频面试题整理,附答案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试官问:怎么自动检测你使用的组件库有更
- 下一篇: 前端学习(2974):组件重定向