為什么要紙上代碼?很多重視技術(shù)的互聯(lián)網(wǎng)公司在工程師招聘的技術(shù)面環(huán)節(jié)都會要求候選人在紙上寫代碼(后文用“紙上代碼”代稱),面試官想通過這種方式考察哪些點?候選人該注意哪些點?本文基于美團早幾年常用的一道區(qū)分度比較高的面試題來做詳細講解,這道題我現(xiàn)在還在用,面過的人很多,但是紙上代碼環(huán)節(jié)能答到滿分的少之又少。
本文為《破解前端面試》系列文章的第 3 篇,前 2 篇鏈接在這里:閉包篇、DOM 篇。
紙上代碼(也有可能在白板上寫)的做法乍看起來不夠人性,但如果你是團隊的 Leader,什么樣的人能更好的融入團隊?如果你是老板,你愿意掏錢養(yǎng)什么樣的員工?紙上代碼的基本目的就是考察候選人是否具備出活的能力,附帶考察候選人是否思路靈活、知識面廣。
紙上代碼環(huán)節(jié)怎么考察出活的能力?首先是出活的速度,沒有編碼基本功的人快速出活的概率是極低的,100% 依賴百度或者 IDE 自動完成才能完成基本任務(wù)的工程師算不上合格的工程師;其次是出活的質(zhì)量,通過編碼過程可以了解候選人通過學(xué)習(xí)和訓(xùn)練積累下來的編碼風(fēng)格、思考方法等;此外,通過紙上代碼也可以了解候選人接受和完成任務(wù)的主動性,是不是愿意接受任何團隊需要完成的任務(wù)。
某種程度上說,紙上代碼過程就是今后工作的縮影,既然如此,面試時排練下不是挺好的么?
紙上代碼該怎么做?通常來說,紙上代碼都不會問特別復(fù)雜的問題,很可能只是完成非常通用的需求,解決實際遇到的業(yè)務(wù)問題,或者用某種語言實現(xiàn)某種算法。在提出實際業(yè)務(wù)問題的代碼題之前,面試官會通過部分前置問題了解候選人對解決業(yè)務(wù)問題所需知識的掌握程度,并在必要的情況下給出知識補充。
比如,前文提到的那道美團的代碼題是:不借助第三方庫的條件下,用 JS 編寫函數(shù)從下面的 URL 串中解析出所有的參數(shù):
http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&d&enabled
期望的返回結(jié)果格式如下:
{ user: "anonymous", id: [123, 456], // 重復(fù)出現(xiàn)的 key 要組裝成數(shù)組,能被轉(zhuǎn)成數(shù)字的就轉(zhuǎn)成數(shù)字類型 city: "北京", // 中文 enabled: true, // 未指定值的 key 約定值為 true }
對于使用過 Node.js 中的 querystring 或者社區(qū)中的 qs、uri.js 模塊的同學(xué)對這個可能再熟悉不過了,而那些不熟 HTTP GET 請求參數(shù)攜帶方式的候選人也不用著急,因為這種情況下面試官會解釋 URL 參數(shù)的構(gòu)造規(guī)則,至于對網(wǎng)絡(luò)知識的掌握程度,是另外的關(guān)注點了。實際操作中,在我拿出這個問題之前,已經(jīng)跟候選人聊了比較多的 HTTP 話題了。
1. 開始動手前相當比例的候選人拿到問題,會立即提筆開始寫代碼,這是面試官最不愿看到的,和學(xué)??荚嚨奶羁疹}不同,紙上代碼作為綜合素質(zhì)環(huán)節(jié),面試官希望看到全面的你,如果工作中也是這樣拿到需求不分青紅皂白就開搞,最終的結(jié)果可能常常是事倍功半。
謀定而后動,動手前一定要搞清楚問題。怎樣才算是把問題搞清楚了?要清楚輸入的特征,是否會出現(xiàn)各種奇怪的輸入(腦子里面有這根弦的人通常不會差,但是面試官會小心求證,看看你能想到哪些);要清楚對解決辦法的其他約束條件,比如時間復(fù)雜度,空間復(fù)雜度。而搞清楚問題的方法就是追問面試官,比如,針對上面的代碼,可以追問的問題:
未指定值的 key 是否會重復(fù)出現(xiàn)?如果重復(fù)出現(xiàn)該怎么處理?
數(shù)字中只包含整數(shù)?是否包含浮點數(shù)?科學(xué)計數(shù)法?
對代碼的性能要求是怎樣的?提出這個問題的時候,候選人心中可能已經(jīng)有多重方法了。
就如同在實際工作中接需求的時候,需要知道需求的邊界,各種可能的特殊情況,合作方對于排期的期望,需求中各個要點優(yōu)先級界定,從決策論的角度來看,掌握更充分的信息,才能讓你對技術(shù)復(fù)雜度、需求排期有更合理的預(yù)估,避免在做到一半或做完的時候發(fā)現(xiàn)與實際需求不符。
搞清楚問題之后,相信你心中已經(jīng)有了基本思路,不過動手的時機還沒到,你應(yīng)該把思路介紹給面試官,確認自己是否自己是否忽略了某些要點,這也是展示溝通能力的好機會,知道什么是有效溝通的同學(xué)應(yīng)該能明白接收信息后向信源確認的重要性。
需要注意的是,質(zhì)疑精神強烈的同學(xué)在動手前會提很多問題,看起來是好事情,但如果只是停留在質(zhì)疑層面,不愿意動手,留給面試官的印象就會是你是個挑活的人。在我的招聘經(jīng)歷中就曾遇到過因為覺得代碼題要解決的問題沒有任何意義而拒絕寫代碼的人,我沒辦法只能客氣的把他送走。因為,對不認同事物的寬容程度很低的人很容易給團隊帶來壞味道。
確定了問題邊界和解決問題的思路,接下來你可以開始動手編碼。
2. 編碼過程中解決 QueryString 參數(shù)解析問題的思路有好多種,比如字符串線性遍歷法、字符串分割法、正則表達式方法,在我面過的人中,用字符串分割法的人最多,下面的討論我們就圍繞這種方法展開。線性遍歷法的實現(xiàn)可以參考 Node.js 內(nèi)置的 querystring 模塊。
編碼過程中需要考慮哪些要素呢?下面用具體的例子來分析,比如我經(jīng)常拿到這樣的結(jié)果代碼:
function parse(str) { var obj = {}; var ary = str.split("&"); for (var i = 0; i < ary.length; i++) { var tmp = ary[i].split("="); if (!obj[tmp[0]]) { obj[tmp[0]] = tmp[1] || true; } else { var tmp2 = [obj[tmp[0]], tmp[1] || true]; obj[tmp[0]] = tmp2; } } return obj; }
看到這樣的代碼,相信你也已經(jīng)皺起了眉頭,這段代碼在表層、邏輯嚴謹性、健壯性都存在問題,更嚴重的是沒有滿足數(shù)值型參數(shù)的需求,透過這段代碼也可以推斷候選人大概率是個不善于學(xué)習(xí)的人。
表層問題表層問題主要指代碼可讀性,評價標準是:是否看起來簡潔?是否看一眼就能理解它在做什么?上面的結(jié)果有哪些具體的表層問題呢?
可讀性方面,如果你想在循環(huán)體里面要追蹤解析到的鍵值對,需要在大腦中保持映射 key = tmp[0], value = tmp[1];
變量命名方面,比如 tmp 的多次使用,ary 代稱數(shù)組雖然也可以,社區(qū)中用 arr 比較多,變量命名多用約定俗成的會更好;
做了表層改進的參考代碼如下:
function parse(str) { var paramObj = {}; var paramArr = str.split("&"); for (var i = 0; i < paramArr.length; i++) { var tmp = paramArr[i].split("="); // 把 key 和 value 多帶帶拆開來,會清晰很多 var key = tmp[0]; var value = tmp[1] || true; if (!paramObj[key]) { paramObj[key] = value; } else { var newValue = [paramObj[key], value]; paramObj[key] = newValue; } } return paramObj; }邏輯問題
邏輯不嚴謹?shù)拇a在不同輸入情況下的結(jié)果是不穩(wěn)定的,具體表現(xiàn)為:
obj[tmp[0]] 不能正確判斷結(jié)果中是否已經(jīng)存在某個 key,因為可能出現(xiàn)值為 0 的情況;
上面的代碼不能正確處理重復(fù)出現(xiàn) 2 次以上的 key,部分候選人到面試結(jié)束還沒想明白為啥;
按照規(guī)范,URL 中的的各種參數(shù)需要在 encode 之后拼接到 URL 中,對應(yīng)的解析時需要 decode;
解決掉邏輯問題的參考代碼如下:
function parse(str) { var paramObj = {}; var paramArr = decoeURI(str).split("&"); // 先解碼 for (var i = 0; i < paramArr.length; i++) { var tmp = paramArr[i].split("="); var key = tmp[0]; var value = tmp[1] || true; if (typeof paramObj[key] === "undefined") { // 判斷 key 是否存在 paramObj[key] = value; } else { var newValue = Array.isArray(paramObj[key]) ? paramObj[key] : [paramObj[key]]; // 正確處理數(shù)組 newValue.push(value); paramObj[key] = newValue; } } return paramObj; }健壯問題
整段代碼沒有做任何的防御性編程,會讓它很容報錯,哪些地方該做防御性編程是值得拿捏的問題。QueryString 解析函數(shù)至少要要求自己的參數(shù)是字符串吧?在函數(shù)開頭增加如下代碼會更好:
//... if (typeof str !== "string") { return {}; } //...需求問題
代碼中沒有對數(shù)字做任何處理,拿到問題就埋頭寫代碼的候選人幾乎都有這個問題,這個問題的考點是怎么把能轉(zhuǎn)換成數(shù)字的值轉(zhuǎn)成數(shù)字。你想好怎么做了么?用 parseInt?還是用 parseFloat?
下面是能正確處理數(shù)字的參考代碼:
function parse(str) { if (typeof str !== "string") { return {}; } var paramObj = {}; var paramArr = decodeURI(str).split("&"); for (var i = 0; i < paramArr.length; i++) { var tmp = paramArr[i].split("="); var key = tmp[0]; var value = tmp[1] || true; // 處理數(shù)字:很多人忽略這里的類型判斷,布爾值傳給 Number 也會解析出數(shù)字 if (typeof value === "string" && isNaN(Number(value)) === false) { value = Number(value); } if (typeof paramObj[key] === "undefined") { paramObj[key] = value; } else { var newValue = Array.isArray(paramObj[key]) ? paramObj[key] : [paramObj[key]]; newValue.push(value); paramObj[key] = newValue; } } return paramObj; }不算問題的問題
下面兩點不算是問題,但是如果候選人能做到,無疑是加分項。
在 ES6 成為新語言標準的情形下,候選人還在大量的使用 var,雖然并沒有錯,但是你要有沒有更好的方法;
可以用更語義化的 JS 數(shù)組方法來組織代碼,比如 map、reduce,如果你知道的化,在面試中可以大膽使用;
使用 ES6 編寫的參考代碼如下:
function parse(str) { if (typeof str !== "string") { return {}; } return decodeURI(str).split("&").map(param => { const tmp = param.split("="); const key = tmp[0]; let value = tmp[1] || true; if (typeof value === "string" && isNaN(Number(value)) === false) { value = Number(value); } return { key, value }; }).reduce((params, item) => { const { key, value } = item; if (typeof params[key] === "undefined") { params[key] = value; } else { params[key] = Array.isArray(params[key]) ? params[key] : [params[key]]; params[key].push(value); } return params; }, {}); }
此外,關(guān)注前端技術(shù)進展的同學(xué)可能會注意到部分現(xiàn)代瀏覽器提供了 URLSearchParams 的支持,可以用這個特性 1 行代碼就搞定需求。
3. 編碼結(jié)束后代碼初版寫完之后,不要著急馬上展示給面試官,就像是需求開發(fā)完,你至少得自己先按需求文檔走一遍,把代碼原題中的輸入代進自己的代碼做推演和簡單的邊界測試,然后再對著代碼和面試官講解。不出意外的話,推演過程你自己會發(fā)現(xiàn)部分問題,或者明顯的改進點,這些內(nèi)容你都可以跟面試官提出來,因為這也是展示你的能力的機會。
總結(jié)感謝你花時間讀到這里,相信你已經(jīng)理解了通過紙上代碼的過程和結(jié)果可以深入考察候選人的基本素質(zhì)、工作方式、出活能力,也知道了在解答代碼題的不同環(huán)節(jié)該注意哪些要點:動手前搞清楚問題;編碼時注意編碼風(fēng)格、邏輯嚴謹性、程序健壯性;編碼后要先自己測試和推演。當然,如果你之前沒注意到這些,需要接下來工作中多加練習(xí)。最后祝你能找到你想要的工作。
One More Thing本文作者王仕軍,商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。如果你覺得本文對你有幫助,請點贊!如果對文中的內(nèi)容有任何疑問,歡迎留言討論。想知道我接下來會寫些什么?歡迎訂閱我的掘金專欄或知乎專欄:《前端周刊:讓你在前端領(lǐng)域跟上時代的腳步》。
Happy Hacking
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83255.html
摘要:技術(shù)周刊的前端重構(gòu)模塊現(xiàn)狀系列文章初探前端每周清單發(fā)布破解前端面試系列如何搞定紙上代碼環(huán)節(jié) FEX 技術(shù)周刊Airbnb 的前端重構(gòu)Javascript 模塊現(xiàn)狀WebAssembly系列文章初探 Headless Chrome前端每周清單:Node.js v8.0發(fā)布;破解前端面試系列(3):如何搞定紙上代碼環(huán)節(jié)?
摘要:下面是本周精選內(nèi)容,請享用。不要看錯了,這個是,和測試框架僅一字之差。本文作者王仕軍,商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。想知道我接下來會寫些什么歡迎訂閱我的掘金專欄或知乎專欄前端周刊讓你在前端領(lǐng)域跟上時代的腳步。 showImg(https://segmentfault.com/img/remote/1460000009646412); 破解前端面試系列文章本周出到第 ...
摘要:醞釀許久之后,筆者準備接下來撰寫前端面試題系列文章,內(nèi)容涵蓋瀏覽器框架分鐘搞定常用基礎(chǔ)知識前端掘金基礎(chǔ)智商劃重點在實際開發(fā)中,已經(jīng)非常普及了。 這道題--致敬各位10年阿里的前端開發(fā) - 掘金很巧合,我在認識了兩位同是10年工作經(jīng)驗的阿里前端開發(fā)小伙伴,不但要向前輩學(xué)習(xí),我有時候還會選擇另一種方法逗逗他們,拿了網(wǎng)上一道經(jīng)典面試題,可能我連去阿里面試的機會都沒有,但是我感受到了一次面試1...
摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...
摘要:問題是這些服務(wù)都是第三方提供的,不能保證它們的響應(yīng)時間,快的話美團點評分布式生成系統(tǒng)后端掘金背景在復(fù)雜分布式系統(tǒng)中,往往需要對大量的數(shù)據(jù)和消息進行唯一標識。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進階-多線程開發(fā)關(guān)鍵技術(shù) - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請務(wù)必將下面這段話置于文章...
閱讀 2275·2021-11-22 09:34
閱讀 2070·2021-09-22 15:22
閱讀 2049·2019-08-29 15:05
閱讀 2141·2019-08-26 10:43
閱讀 3437·2019-08-26 10:26
閱讀 926·2019-08-23 18:29
閱讀 3551·2019-08-23 16:42
閱讀 2023·2019-08-23 14:46