亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

80%應(yīng)聘者都不及格的JS面試題

 更新時(shí)間:2017年03月21日 09:54:41   作者:王仕軍  
超過80%的候選人對下面這道JS面試題的回答情況連及格都達(dá)不到。這究竟是怎樣神奇的一道JS面試題?他考察了候選人的哪些能力?對正在讀本文的你有什么啟示?

共 5024 字,讀完需 6 分鐘,速讀需 2 分鐘,本文首發(fā)于知乎專欄前端周刊。寫在前面,筆者在做面試官這 2 年多的時(shí)間內(nèi),面試了數(shù)百個(gè)前端工程師,驚訝的發(fā)現(xiàn),超過 80% 的候選人對下面這道題的回答情況連及格都達(dá)不到。這究竟是怎樣神奇的一道面試題?他考察了候選人的哪些能力?對正在讀本文的你有什么啟示?且聽我慢慢道來

不起眼的開始

招聘前端工程師,尤其是中高級(jí)前端工程師,扎實(shí)的 JS 基礎(chǔ)絕對是必要條件,基礎(chǔ)不扎實(shí)的工程師在面對前端開發(fā)中的各種問題時(shí)大概率會(huì)束手無策。在考察候選人 JS 基礎(chǔ)的時(shí)候,我經(jīng)常會(huì)提供下面這段代碼,然后讓候選人分析它實(shí)際運(yùn)行的結(jié)果:

for (var i = 0; i < 5; i++) {
 setTimeout(function() {
 console.log(new Date, i);
 }, 1000);
}

console.log(new Date, i);

這段代碼很短,只有 7 行,我想,能讀到這里的同學(xué)應(yīng)該不需要我逐行解釋這段代碼在做什么吧。候選人面對這段代碼時(shí)給出的結(jié)果也不盡相同,以下是典型的答案:

A. 20% 的人會(huì)快速掃描代碼,然后給出結(jié)果:0,1,2,3,4,5;
B. 30% 的人會(huì)拿著代碼逐行看,然后給出結(jié)果:5,0,1,2,3,4;
C. 50% 的人會(huì)拿著代碼仔細(xì)琢磨,然后給出結(jié)果:5,5,5,5,5,5;

只要你對 JS 中同步和異步代碼的區(qū)別、變量作用域、閉包等概念有正確的理解,就知道正確答案是 C,代碼的實(shí)際輸出是:

2017-03-18T00:43:45.873Z 5
2017-03-18T00:43:46.866Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5

接下來我會(huì)追問:如果我們約定,用箭頭表示其前后的兩次輸出之間有 1 秒的時(shí)間間隔,而逗號(hào)表示其前后的兩次輸出之間的時(shí)間間隔可以忽略,代碼實(shí)際運(yùn)行的結(jié)果該如何描述?會(huì)有下面兩種答案:

A. 60% 的人會(huì)描述為:5 -> 5 -> 5 -> 5 -> 5,即每個(gè) 5 之間都有 1 秒的時(shí)間間隔;
B. 40% 的人會(huì)描述為:5 -> 5,5,5,5,5,即第 1 個(gè) 5 直接輸出,1 秒之后,輸出 5 個(gè) 5;

這就要求候選人對 JS 中的定時(shí)器工作機(jī)制非常熟悉,循環(huán)執(zhí)行過程中,幾乎同時(shí)設(shè)置了 5 個(gè)定時(shí)器,一般情況下,這些定時(shí)器都會(huì)在 1 秒之后觸發(fā),而循環(huán)完的輸出是立即執(zhí)行的,顯而易見,正確的描述是 B。

如果到這里算是及格的話,100 個(gè)人參加面試只有 20 人能及格,讀到這里的同學(xué)可以仔細(xì)思考,你及格了么?

追問 1:閉包

如果這道題僅僅是考察候選人對 JS 異步代碼、變量作用域的理解,局限性未免太大,接下來我會(huì)追問,如果期望代碼的輸出變成:5 -> 0,1,2,3,4,該怎么改造代碼?熟悉閉包的同學(xué)很快能給出下面的解決辦法:

for (var i = 0; i < 5; i++) {
 (function(j) { // j = i
 setTimeout(function() {
  console.log(new Date, j);
 }, 1000);
 })(i);
}

console.log(new Date, i);

巧妙的利用 IIFE(Immediately Invoked Function Expression:聲明即執(zhí)行的函數(shù)表達(dá)式)來解決閉包造成的問題,確實(shí)是不錯(cuò)的思路,但是初學(xué)者可能并不覺得這樣的代碼很好懂,至少筆者初入門的時(shí)候這里琢磨了一會(huì)兒才真正理解。

有沒有更符合直覺的做法?答案是有,我們只需要對循環(huán)體稍做手腳,讓負(fù)責(zé)輸出的那段代碼能拿到每次循環(huán)的 i 值即可。該怎么做呢?利用 JS 中基本類型(Primitive Type)的參數(shù)傳遞是按值傳遞(Pass by Value)的特征,不難改造出下面的代碼:

var output = function (i) {
 setTimeout(function() {
 console.log(new Date, i);
 }, 1000);
};

for (var i = 0; i < 5; i++) {
 output(i); // 這里傳過去的 i 值被復(fù)制了
}

console.log(new Date, i);

能給出上述 2 種解決方案的候選人可以認(rèn)為對 JS 基礎(chǔ)的理解和運(yùn)用是不錯(cuò)的,可以各加 10 分。當(dāng)然實(shí)際面試中還有候選人給出如下的代碼:

for (let i = 0; i < 5; i++) {
 setTimeout(function() {
 console.log(new Date, i);
 }, 1000);
}

console.log(new Date, i);

細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),這里只有個(gè)非常細(xì)微的變動(dòng),即使用 ES6 塊級(jí)作用域(Block Scope)中的 let 替代了 var,但是代碼在實(shí)際運(yùn)行時(shí)會(huì)報(bào)錯(cuò),因?yàn)樽詈竽莻€(gè)輸出使用的 i 在其所在的作用域中并不存在,i 只存在于循環(huán)內(nèi)部。

能想到 ES6 特性的同學(xué)雖然沒有答對,但是展示了自己對 ES6 的了解,可以加 5 分,繼續(xù)進(jìn)行下面的追問。

追問 2:ES6

有經(jīng)驗(yàn)的前端同學(xué)讀到這里可能有些不耐煩了,扯了這么多,都是他知道的內(nèi)容,先別著急,挑戰(zhàn)的難度會(huì)繼續(xù)增加。

接著上文繼續(xù)追問:如果期望代碼的輸出變成 0 -> 1 -> 2 -> 3 -> 4 -> 5,并且要求原有的代碼塊中的循環(huán)和兩處 console.log 不變,該怎么改造代碼?新的需求可以精確的描述為:代碼執(zhí)行時(shí),立即輸出 0,之后每隔 1 秒依次輸出 1,2,3,4,循環(huán)結(jié)束后在大概第 5 秒的時(shí)候輸出 5(這里使用大概,是為了避免鉆牛角尖的同學(xué)陷進(jìn)去,因?yàn)?JS 中的定時(shí)器觸發(fā)時(shí)機(jī)有可能是不確定的,具體可參見 How Javascript Timers Work)。

看到這里,部分同學(xué)會(huì)給出下面的可行解:

for (var i = 0; i < 5; i++) {
 (function(j) {
 setTimeout(function() {
  console.log(new Date, j);
 }, 1000 * j)); // 這里修改 0~4 的定時(shí)器時(shí)間
 })(i);
}

setTimeout(function() { // 這里增加定時(shí)器,超時(shí)設(shè)置為 5 秒
 console.log(new Date, i);
}, 1000 * i);

不得不承認(rèn),這種做法雖粗暴有效,但是不算是能額外加分的方案。如果把這次的需求抽象為:在系列異步操作完成(每次循環(huán)都產(chǎn)生了 1 個(gè)異步操作)之后,再做其他的事情,代碼該怎么組織?聰明的你是不是想起了什么?對,就是 Promise。

可能有的同學(xué)會(huì)問,不就是在控制臺(tái)輸出幾個(gè)數(shù)字么?至于這樣殺雞用牛刀?你要知道,面試官真正想考察的是候選人是否具備某種能力和素質(zhì),因?yàn)樵诂F(xiàn)代的前端開發(fā)中,處理異步的代碼隨處可見,熟悉和掌握異步操作的流程控制是成為合格開發(fā)者的基本功。

順著下來,不難給出基于 Promise 的解決方案(既然 Promise 是 ES6 中的新特性,我們的新代碼使用 ES6 編寫是不是會(huì)更好?如果你這么寫了,大概率會(huì)讓面試官心生好感):

const tasks = [];
for (var i = 0; i < 5; i++) { // 這里 i 的聲明不能改成 let,如果要改該怎么做?
 ((j) => {
 tasks.push(new Promise((resolve) => {
  setTimeout(() => {
  console.log(new Date, j);
  resolve(); // 這里一定要 resolve,否則代碼不會(huì)按預(yù)期 work
  }, 1000 * j); // 定時(shí)器的超時(shí)時(shí)間逐步增加
 }));
 })(i);
}

Promise.all(tasks).then(() => {
 setTimeout(() => {
 console.log(new Date, i);
 }, 1000); // 注意這里只需要把超時(shí)設(shè)置為 1 秒
});

相比而言,筆者更傾向于下面這樣看起來更簡潔的代碼,要知道編程風(fēng)格也是很多面試官重點(diǎn)考察的點(diǎn),代碼閱讀時(shí)的顆粒度更小,模塊化更好,無疑會(huì)是加分點(diǎn)。

const tasks = []; // 這里存放異步操作的 Promise
const output = (i) => new Promise((resolve) => {
 setTimeout(() => {
 console.log(new Date, i);
 resolve();
 }, 1000 * i);
});

// 生成全部的異步操作
for (var i = 0; i < 5; i++) {
 tasks.push(output(i));
}

// 異步操作完成之后,輸出最后的 i
Promise.all(tasks).then(() => {
 setTimeout(() => {
 console.log(new Date, i);
 }, 1000);
});

讀到這里的同學(xué),恭喜你,你下次面試遇到類似的問題,至少能拿到 80 分。

我們都知道使用 Promise 處理異步代碼比回調(diào)機(jī)制讓代碼可讀性更高,但是使用 Promise 的問題也很明顯,即如果沒有處理 Promise 的 reject,會(huì)導(dǎo)致錯(cuò)誤被丟進(jìn)黑洞,好在新版的 Chrome 和 Node 7.x 能對未處理的異常給出 Unhandled Rejection Warning,而排查這些錯(cuò)誤還需要一些特別的技巧(瀏覽器、Node.js)。

追問 3:ES7

既然你都看到這里了,那就再堅(jiān)持 2 分鐘,接下來的內(nèi)容會(huì)讓你明白你的堅(jiān)持是值得的。

多數(shù)面試官在決定聘用某個(gè)候選人之前還需要考察另外一項(xiàng)重要能力,即技術(shù)自驅(qū)力,直白的說就是候選人像有內(nèi)部的馬達(dá)在驅(qū)動(dòng)他,用漂亮的方式解決工程領(lǐng)域的問題,不斷的跟隨業(yè)務(wù)和技術(shù)變得越來越牛逼,究竟什么是牛逼?建議閱讀程序人生的這篇剖析。

回到正題,既然 Promise 已經(jīng)被拿下,如何使用 ES7 中的 async await 特性來讓這段代碼變的更簡潔?你是否能夠根據(jù)自己目前掌握的知識(shí)給出答案?請?jiān)谶@里暫停 1 分鐘,思考下。

下面是筆者給出的參考代碼:

// 模擬其他語言中的 sleep,實(shí)際上可以是任何異步操作
const sleep = (timeountMS) => new Promise((resolve) => {
 setTimeout(resolve, timeountMS);
});

(async () => { // 聲明即執(zhí)行的 async 函數(shù)表達(dá)式
 for (var i = 0; i < 5; i++) {
 await sleep(1000);
 console.log(new Date, i);
 }

 await sleep(1000);
 console.log(new Date, i);
})();

總結(jié)

感謝你花時(shí)間讀到這里,相信你收獲的不僅僅是用 JS 精確控制代碼輸出的各種技巧,更是對于前端工程師的成長期許:扎實(shí)的語言基礎(chǔ)、與時(shí)俱進(jìn)的能力、強(qiáng)大技術(shù)自驅(qū)力。

更多面試題學(xué)習(xí)資料請關(guān)注專題《面試題大全》 。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JavaScript實(shí)現(xiàn)滑塊驗(yàn)證碼

    JavaScript實(shí)現(xiàn)滑塊驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)滑塊驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 原生JS實(shí)現(xiàn)不斷變化的標(biāo)簽

    原生JS實(shí)現(xiàn)不斷變化的標(biāo)簽

    這篇文章主要介紹了原生JS實(shí)現(xiàn)不斷變化的標(biāo)簽,可以上下浮動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 一文詳解為什么JavaScript中的JSON.parse()報(bào)錯(cuò)

    一文詳解為什么JavaScript中的JSON.parse()報(bào)錯(cuò)

    這篇文章主要介紹了JavaScript中JSON.parse()方法的使用和常見錯(cuò)誤,包括非法JSON格式、包含不可解析的字符、使用單引號(hào)等,并提供了相應(yīng)的解決方案和實(shí)際項(xiàng)目中的代碼示例,需要的朋友可以參考下
    2025-03-03
  • location.href語句與火狐不兼容的問題

    location.href語句與火狐不兼容的問題

    在寫JS跳轉(zhuǎn)語句的過程中,發(fā)現(xiàn)這么一個(gè)問題,location.href語句與火狐不兼容的問題
    2010-07-07
  • JavaScript?Echarts柱狀圖label優(yōu)化中問題針對講解

    JavaScript?Echarts柱狀圖label優(yōu)化中問題針對講解

    這篇文章主要介紹了JavaScript?Echarts柱狀圖label優(yōu)化中問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • 微信小程序 bindtap 傳參的實(shí)例代碼

    微信小程序 bindtap 傳參的實(shí)例代碼

    這篇文章主要介紹了微信小程序 bindtap 傳參的實(shí)例代碼,代碼簡單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • js中判斷一個(gè)數(shù)是不是素?cái)?shù)的三種方法例子

    js中判斷一個(gè)數(shù)是不是素?cái)?shù)的三種方法例子

    這篇文章主要給大家介紹了關(guān)于js中如何判斷一個(gè)數(shù)是不是素?cái)?shù)的三種方法,素?cái)?shù)(只能被1和本身整除的數(shù))規(guī)律:把這個(gè)數(shù)除以它之前的每一個(gè)數(shù)(從2開始)只要找到一個(gè)整除(余數(shù)為0)就是非素?cái)?shù),需要的朋友可以參考下
    2023-10-10
  • JS簡單設(shè)置下拉選擇框默認(rèn)值的方法

    JS簡單設(shè)置下拉選擇框默認(rèn)值的方法

    這篇文章主要介紹了JS簡單設(shè)置下拉選擇框默認(rèn)值的方法,涉及javascript針對頁面元素的遍歷、查找及設(shè)置技巧,需要的朋友可以參考下
    2016-08-08
  • JavaScript替換當(dāng)前頁面的方法

    JavaScript替換當(dāng)前頁面的方法

    這篇文章主要介紹了JavaScript替換當(dāng)前頁面的方法,涉及javascript中replace方法的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • js實(shí)現(xiàn)精美的銀灰色豎排折疊菜單

    js實(shí)現(xiàn)精美的銀灰色豎排折疊菜單

    這篇文章主要介紹了js實(shí)現(xiàn)精美的銀灰色豎排折疊菜單,可實(shí)現(xiàn)頁面左側(cè)豎排的縱向折疊菜單效果,非常美觀實(shí)用,需要的朋友可以參考下
    2015-05-05

最新評論