前端開發面試快速復盤,不標准的面試經驗分享(三),逃離湖泊投身大海的魚


壹 ❀ 引

大致上來說,這是我認真找工作的第二周了,比較遺憾,到目前為止我仍為找到滿意的工作。倘若你問我找工作難不難,單站在找到工作的角度其實並不難,但如果在找到的基礎上增加一些條件就比較難了。就像兩個年輕人准備談戀愛,首先得互相看對眼才有初步機會,若一方要求較高那么在一起的概率就會降低。在本周我從面試邀請中挑了三家看似不錯公司並參加了面試,大致都是有成熟上線項目的技術自研型公司。本篇文章中的問題可能與之前的面試復盤存在一定差異,文章較長但我還是希望你能耐心讀完,並假想當時被問到的是自己又該如何作答,這對於日后大家挑戰高級開發崗位多多少少會有幫助(雖然我自己都還沒成功),那么本文開始。

貳 ❀ 阿里某合作商

這是一家為阿里巴巴提供雲計算服務的公司,技術算很硬了,要求也很高。我在周二晚上接的電話一面,后來才知道電話對面是他們公司的技術總監,談話內容主要圍繞JS基礎問題,大致如下(注意,下文中面試自我介紹我都省略了):

面:你在上家公司扮演了什么角色?主要負責了哪些工作?

角色方面如實作答就好了,負責工作可圍繞在職期間自己工作出色點,或者其它能體現自己能力的方面作答,不要僅限於寫代碼。比如我在項目重構方面出力較多,也負責了項目組件庫的開發,因為個人JS基礎知識儲備還行,所以也有帶見習開發的工作,所以我就圍繞這三個方面說了,大家可以構思總結下自己的工作出色點。

面:能說下深拷貝嗎?

深拷貝是針對引用數據出現的問題,引用我們將一個對象A賦予對象B時,對象B保存的其實是A對象值存放地址的引用,所以如論修改A還是B,都會影響另一方。而深拷貝就是要達到復制對象后,修改任意一方都不會影響另一方。

面:那你能不能實現一個深拷貝?說下實現時需要考慮的邊界問題

單說實現,乞丐版可以依賴JSON的parsestringify做到,當然面試官肯定不會滿足於此,一定會追問你如果自己實現怎么辦,所以后面我就聊了下自己如何實現一個簡單的深拷貝(只針對對象{}和數組),以及實現需要考慮的邊界問題。

先說邊界問題,假設我們要實現一個深拷貝函數deepCopy,因為前面說了深拷貝是針對引用數據來說的,第一點,傳進來的參數一定是得檢驗數據數據類型,若是基礎類型就沒拷貝的必要了。第二點,對象的屬性值也可能是一個對象,因此在復制時還得對值進行判斷,若仍然是對象,我們得遞歸。第三點,我們拷貝對象自然是希望拷貝對象自身屬性,而對於非自身的繼承屬性我們得過濾掉,那么我們來實現一個簡單的深拷貝:

// 只針對{}與數組的簡單實現
function deepCopy(source) {
    function isObject(o) {
        // 此實現只針對數組與{},由於null的typeof類型也是object,特做過濾
        return typeof o === 'object' && o !== null;
    };
    // 如果參數不是對象{}或數組直接返回
    if (!isObject(source)) {
        return source;
    };
    // 創建一個新對象,是數組就創建空數組,反之空對象
    let target = Array.isArray(source) ? [] : {};
    // 遍歷源對象,進行拷貝
    for (key in source) {
        // 判斷當前屬性是否是自身屬性
        if (source.hasOwnProperty(key)) {
            // 判斷當前屬性的值是否仍然是對象
            if (isObject(source[key])) {
                target[key] = deepCopy(source[key])
            } else {
                target[key] = source[key];
            };
        };
    };
    return target;
};

面:ES6了解嗎?說下你熟悉的特性,說三條就好。

這個比較簡單,我首先說了下let const,關聯性的介紹了塊級作用域,暫時性死域,const值是引用對象時不能修改的是引用地址,之后聊了下箭頭函數與this,之后說了promise,三個狀態,all與race的區別之類的,大家挑自己熟悉的去說,能扯的詳細更好。

面:做過哪些優化工作?

這個說起來的方面就多了,比如文件下載方法的優化,對於每個頁面盡可能做到按需加載,減少非必要文件的下載,還可以使用http緩存,文件MD5戳減少文件下載頻率,結合發布工具壓縮合並文件等;代碼層面的優化,比如組件封裝,常用API封裝,減少代碼量提升代碼復用性;使用友好方面優化,比如圖片懶加載,onloading管理,節流防抖等等。

一面大致問了這些問題,面試官對於我的回答還算滿意,初面給我的評價是知識體系很系統化,思考問題也很全面,所以周四下午約了現場復試,復試兩個面試官排隊問,那么下面是復試相關問題:

面:看你項目重構做的比較多,說下重構做了哪些工作

對於這個問題我開始詳細說了下項目結構調整,因為我當時重構並不是在原有基礎上改寫代碼,而是對整個項目進行了從零開始的重寫,包括項目結構調整,由最初一個總應用APP文件管理了所有頁面的service,組件相關注冊,改為APP文件只負責注冊,單頁面分別管理自身所需依賴文件。

這么做的的目的主要還是按需加載,A頁面用到什么便注冊什么,頁面渲染時可以減少不必要的文件下載。其余文件更便於管理,哪個service為誰服務一路了然。

之后介紹了組件封裝之類的相關重構工作,以及發布工具配置等相關的。

面:能說下你組件封裝的思路嗎?

第一步確認需求,在了解需求的情況下繪制流程圖,再以流程圖與上級確認需求是否符合,可行的話之后就是看着圖寫代碼的事情了。

面:那你怎么保證組件重構封裝后還能滿足之前的業務需求,舉個例子,假設之前組件是滿足ABC三種情況的,但因為需求文檔疏忽,或者你自己流程圖的疏忽忽略了B,你該怎么彌補這個問題?

老實說,我一是沒遇到過這種問題,二是實在沒get到他具體想問的點在哪....后面回答也不是很好,所以直接征求面試官合理的做法了。面試官說這個問題解決方案很多,比如可以在組件實現后可進行單元測試,這樣就能提前知道B不符合情況了,之后修改組件邏輯的同時完善需求文檔。我聽完人都傻了...我一直以為他想問的是組件設計方面的問題,比如如何保證組件拓展性,所以當時回答的很失敗了。

面:你在組件里有提到loading的實現,如果一個請求很快就結束了,你怎么處理的?

因為我的loading在請求攔截處統一管理,request階段啟動,response階段關閉,由於請求都是同步,異步是響應階段,一個頁面總是會存在多個請求的情況,所以開啟loading只會有一次,且開啟loading是由定時器管理,比如2S后才會啟用loading,如果一個網絡請求非常快,則會將啟動loading的定時器清除。而針對多個請求,會用數組裝在每個請求信息,完成一個請求對應清除數組中該請求信息,數組被清空時自然說明請求全部完成,則關閉loading。

面:你說在請求攔截中做了部分網絡錯誤處理,那如果一個請求超時了怎么辦?

針對於請求超時,可以通過retry來實現自動發起再次請求。隨后面試官又問retry需要注意什么,這里我就說了retry需要設置最大retry次數,避免無限請求,其次retry之間也需要設置間隔時間。

面:那你是對整個項目所有請求都retry了嗎,如果有些請求我不想retry怎么辦?

這里我實際的做法是在項目配置文件中,專門有一個數組裝了需要retry的接口信息,如果一個接口沒被包含,就不會執行retry,類似於多了一次條件判斷。

面:你前面說retry是根據code 504來做的,如果有些請求,后台沒返回,也就是沒有respone,你怎么做后續處理?

這個我當時答的也不是很好,其實不管后台有沒有返回,前端都是可以拿到反饋信息的,哪怕我們請求一個不存在的接口,也會得到接口404的錯誤反饋,所以針對反饋的錯誤信息去做處理,給出提示或者其它。

面:能說下你做的多貨幣功能嗎?

這個我就大致介紹了多貨幣指令的實現,當貨幣在美元與人民幣之間切換時,會觸發指令邏輯,根據后台提前返回的匯率進行計算,其實我說到這我就猜到會問精度問題了,但是這塊我之前沒詳細了解過。

面:那你前端是如何保證計算后的精度的?比如我們都知道0.1+0.2!=0.3,你說下為什么,如何在計算中解決。

這個我回答的也不是很好,關於0.1+0.2這個問題之前有看,但是時間太久記憶模糊了,只記得是精度丟失,所以沒能很系統的去解釋。

准確來說js中的數字都采用了IEEE 754標准的64位雙精度浮點數,而對於64位的浮點數在內存中表示時分為了三部分,第0位符號位(占1位,用s表示),表示這個數字是正數還是負數,0為正,1表示負數。第1到11位為指數部分(占11位,用e表示),表示這個數值的大小,第12到63位為尾數部分(占52位,用m表示),決定數值的精度,大致如圖:

我們知道計算機中數字都是按二進制進行存儲的,所以第一步得將十進制數值轉為二進制,需要說明的是十進制整數轉二進制方法為除2取余,按倒序排列,而十進制小數轉二進制方法為乘2取整,按順序排列啥意思?我們現在就以0.1為例,0.1整數部分為0,0/2余0,所以先得到一個0.。我們再看小數部分,如下:

0.1 * 2 = 0.2 //取整數0,第一位,0.2參與下次計算
0.2 * 2 = 0.4 //取整數0,第二位,0.4參與下次計算,
0.4 * 2 = 0.8 //取整數0,第三位,0.8參與下次計算
0.8 * 2 = 1.6 //取整數1,第四位,0.6參與下次計算	標記1
0.6 * 2 = 1.2 //取整數1,第五位,0.2參與下次計算
0.2 * 2 = 0.4 //取整數0,第六位,0.4參與下次計算
0.4 * 2 = 0.8 //取整數0,第七位,0.8參與下次計算
0.8 * 2 = 1.6 //取整數1,第八位,0.6參與下次計算  標記2
0.6 * 2 = 1.2 //取整數1,第九位,0.2參與下次計算

請觀察上述計算,在標記1到標記2的位置,再往后其實已經進入了一個循環了,由於計算永遠得不到小數部分為0的情況,所以其實進入了一個無限的計算循環,結合前面得到0.,組合而成就是0.0 0011 0011 0011...(0011循環)

計算機中內存是有限的,所以並不可能去存儲一個無限長的數值,因此計算機在某個精度點自然就舍棄了后面的數字,這個精度點自然就是我們前面說的52位尾數了。所以二進制轉換完成,是還會再按IEEE 754標准再轉一次,轉換公式就不說了,直接給結果:

// 0.1
e = -4;
m = 1.1001100110011001100110011001100110011001100110011010 (52位)

而0.2轉換同樣會存在這樣的問題,所以兩個都丟失了精度的數值計算后還原成十進制,自然得到的不是0.3。具體推算可以閱讀這篇文章詳解js中0.1+0.2!=0.3

當然不是所有浮點數都有誤差,二進制其實能精確地表示位數有限且分母是2的倍數的小數,比如0.5在計算機內部就沒有舍入誤差,所以0.5 + 0.5 === 1。

那么我們怎么比較0.1+0.2===0.3呢?這里其實可以借用ES6中Number的新屬性EPSILON,它表示 1 與Number可表示的大於 1 的最小的浮點數之間的差值,所以正確的比較方式為:

 Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON;// true

當然,關於金額數值的計算,一般都是交給后端計算,如果前端算了其實后端也要算一次做核對,所以總體來說后端一定要算。主要原因是一方面是前端計算存在浮點數問題,處理起來存在一定成本,二是前端可能存在改單情況,存在一定金額計算風險。

當然前端如果說真要算怎么辦,這里可以借用成熟的類庫來解決,比如math.js

面:能說下多語言怎么做的嗎?

多語言用了angularjs的ng-translate指令,考慮大家都沒用過,這里就不細說了。

面:能說下你這個sentry是做什么的嗎?

sentry是一個前端錯誤監控系統,這里我主要是基於sentry搭建了一個前端異常監控服務,用於抓取前端http請求異常,目的是在用戶使用過程中出現請求錯誤時,通過對原錯誤信息進行加工,提取用戶信息,出錯頁面,請求地址,參數,響應數據等相關信息並上傳日志,開發者可通過郵件快速定位錯誤,達到遠程排錯的目的。

面:你覺得你工作中遇到最有難度或者最有挑戰性的事情是什么?比如花了很久時間解決的事。

其實我在面試前就想到如果被人問到這個問題怎么辦,但是我覺得自己項目真的亮點不足,涉及技術點不深,結果這次真遇到了,然后我直說了沒有- -,因為項目太簡單了(在后續聊天中我找到了下次可以回答的答案)。

面:XMLHttpRequest對象了解嗎?

我們熟知的ajax在不刷新頁面情況下,異步更新頁面部分數據,其實底層依賴的就是XMLHttpRequest對象,所以我圍繞ajax使用,大致說了創建xml對象=>利用open設置請求方式與請求地址以及是否異步=>利用send發送請求=>設置監聽函數onreadystatechange函數=>處理響應數據五個過程,介紹了readyState不同狀態的具體含義。

面:fetch了解嗎?跟ajax有什么區別?

說來慚愧,這真是我第一次聽到fetch,所以面試官也很詫異,說這么常用的東西你都不知道....仔細回想這三年,第一年用JQ,后兩年用angularjs內置的http請求,周圍也沒有一個人給我提起過這個詞,那么這里簡單整理下。

首先fetch是原生js的實現方案,與ajax並無關系,你可以把它當成XMLHttpRequest的一種更理想的替代方案,fetch語法如下:

fetch(input[, init])

其中input可以是獲取資源的地址,或者是一個request對象。而init則是一個包含所有請求設置的對象,比如請求方法,headers請求頭信息以及可以使用mode:cors達到跨域效果等等,來看個簡單的例子:

fetch('http://example.com/movies.json')
    .then(function (response) {
        return response.json();
    })
    .then(function (myJson) {
        console.log(myJson);
    });

fetch不管請求成功失敗,都會返回一個promise,我們可以使用then方法處理回調。

ajax對比,fetch主要有三點不同:

  • 當接收一個表示錯誤的http狀態碼時,fetchpromise不會被標記為rejecte,反而是resolve(但是會將resolve的ok屬性設為false),只有網絡故障,請求被阻止這種情況才會被標記reject
  • fetch可以接受跨域cookies,你也可以使用fetch創建跨域請求。
  • fetch默認不會發送cookies,除非我們通過前面的init對象修改了初始化配置。

更多fetch還是推薦大家閱讀MDN使用 Fetch詞條

面:如果讓你對比angularjs和vue,你覺得angularjs優勢在哪?

這個問題就挺頭大了,人人都知道angularjs由於臟檢測機制等歷史遺留問題,官方都放棄了此版本的更新而新開了angular版本,而vue在設計初期借鑒了angularjs一些思想,整體上來說vue是更具優勢的,所以想來想去我回答的是angularjs優勢體現在組件化,mvc思想先驅的角色扮演。

面:那vue相對angularjs你覺得有哪些優勢呢?

這個就好解釋一點了,其實對於我的開發體驗來說,最大的感觸還是angularjs的臟檢測性能問題,angularjs臟檢測原理其實是由digest方法觸發,默認從頂層作用域開始深度遍歷,依次訪問每個作用域中的watcher數組中的每個數據,一一對比是否發生變化,所以如果作用域嵌套多,監聽數據多,每次更新開銷都是巨大的,但相對這一點,vue使用基於依賴追蹤的觀察系統,若一條數據變化只會更新本數據,成本會小很多。其次針對組件通信,angularjs官方並未友好提供兄弟通信的方式,但是在vue中借用vuex等會便捷很多。

面:有了解過設計模式嗎?

面:有推進公司項目,或者技術研究嗎?

面:最近做過哪些技術分享?

這幾個問題就統一說下了,設計模式我之前有讀過JavaScript設計模式相關數據,不過實踐能力較弱,並沒到融會貫通的地步,推進項目我說的是沒有,小嘍嘍一個,技術分享自然是博客了,說了最近就是寫一些面試復盤總結。

大致到這里就算面試結束了,兩個面試官說要討論下結果,順便看下我的博客。大約等了10來分鍾,得到的反饋是項目無亮點,軟件思維薄弱,目前公司只有三個崗位,1個高級2個初級,並沒有適合我的位置。

其實我面完感受也不是很好,我深知自己項目難度不高,沒太多亮點,面對深挖項目的面試我真的毫無優勢,所以結果也算預料之內了,所以我急忙就問了面試官前面我回答的不是很好的問題,面試官笑着說還想着討點面經啊,然后就又跟我閑聊了十來分鍾。

我:我深知自己項目無亮點,難度並不高,所以被問到你覺得工作你做過覺得最有難度的事情時我怎么回答?

面試官說,這個問題其實並不局限於代碼層面,當然如果你確實有花了很大的功夫解決了一個非常困難的問題,自然印象分會更高,如果確實沒有,就可以拓展到工作其它方面,比如你推進了項目進程,在期間付出了很多,扮演了一個核心角色,這樣也能體現出你的溝通,協同,領導能力等等。我聽到這才恍然大悟,之前確實有項目從UI設計初期參與討論,跟后台討論定義定義等等,是有過推進項目的經歷。

我:對於我之后的面試,或者職業發展能不能給我一些建議?

面試官說看過了我的博客,面試總結寫的非常到位,之前初面就是覺得我基礎回答非常出色,所以雖然我不會react但也很感興趣,對我的額外評價是,基礎扎實,學習能力很強,自律,讓我一定要把寫博客的習慣堅持下去,對於后期發展,讓我一定要在某個領域專精,這是到高級必經之路,之后轉架構或者全棧那就是橫向拓展知識面的事情了。

在后面的閑聊中,我才知道他們公司招聘確實算很嚴格了,面試了200多人,只發了2個offer,其中一個去了大廠沒來,最后面試官直言確實很欣賞我,只是公司職位卡的太死,也算是我最后的一點安慰了。

叄 ❀ 某不錯的公司

下午面完了上家復試,晚上六點等來了第二家公司的視頻初面,大家印象里的初面可能都在半小時之內,結果我這個初面面了一個半小時....也算是讓我印象深刻了,那么直接開始。

面:說下你哪個項目最有亮點?

哪個項目最有亮點,做過哪些優化,這些真的是高頻問題了,所以大家一定要總結自己項目的出色點,這個真的是必問,我的回答自然是自己負責的重構項目,說了下優化方面的事情。

面:說下你通用服務,比如指令怎么划分?

我前面說過了我的注冊由早期統一注冊改為了按需加載,所以在重構初期,是對於service,指令做了對應頁面、功能的一個初步划分,比如購物車相關的接口API會統一放在購物車的service中,而關於注冊方面,如果一個指令,服務是整個項目全局使用的,那就全局注冊,如果一個服務是單個頁面使用,那就按需加載去注冊。

面:我看到你項目中有個錯誤code的功能,能說下嗎?

內部的一個小功能了,之前的復盤也總結過,大家看了也沒啥幫助,就不細說了。

面:了解http緩存嗎,能不能說下?

首先http1時期,http緩存靠的是絕對過期時間Expires,也就是第一次請求后,服務端給你一個絕對時間,時間沒到你就不能請求直接用緩存,這樣肯定就很不人性化了。之后http1.1就可以使用Last-Modified來比較文件的修改時間,這也其實也會存在修改時間變了,文件內容沒變的情況,所以還是存在一定問題。而最后就是文件內容唯一標識Etag,只要這個對不上,說明文件變化就可以重新下載更新了。除此之外我也簡單說了下協商性緩存與強緩存的概念。

面:不知道你有沒有了解過,同樣都是緩存,但有時候狀態碼不是304,比如緩存有額外說明from memory cache,有時候是from disk cache,你知道它們區別嗎?

我知道面試官是想問內存緩存與磁盤緩存,真沒想到會問這么深...瀏覽器緩存其實滿足三級緩存原理,即走緩存的情況,先看內存中有沒有緩存,有就取內存;如果內存中沒有,就看磁盤中有沒有,有就取磁盤,如果磁盤都沒有,那就只有再次發起網絡請求,將加載的資源再次緩存到內存和磁盤中。

其次,memory與disk存儲方式以及文件類型也不同,具體如下:

  • 200 form memory cache:不發起請求,從內存中讀取緩存文件,但如果關閉瀏覽器數據將會被釋放,下次再打開頁面就得重新請求了,一般腳本,字體,圖片都存在內存中。
  • 200 form disk cache:不發起請求,從磁盤中讀取緩存,關閉瀏覽器后數據還會存在,所以下次再打開相同頁面還是走緩存,磁盤中一般緩存類似css非腳本文件。

面:http2了解嗎?

這個因為我也未真正用過,其實都是站在理論層面,所以說了下http2的新增特性:

  • http2支持新的二進制格式傳輸文件
  • http2支持通信雙方緩存header表信息,這樣在下次請求能避免重復數據的傳輸
  • http2支持服務端主動推送數據給客戶端。

面:跨域了解嗎?說三種常見的解決方案

這個也是常考題,不過方案除了nginx反向代理,JSONP,window.name結合iframe外,前面我們提到的fetch也是一種不錯的方案。

面:Virtual DOM了解嗎?

因為我並未真正實戰過vue和react,這塊的理解是很薄弱的,所以就直說不是很了解了,關於虛擬DOM可以深入閱讀你不知道的Virtual DOM系列文章。

在面試官確信我不知道虛擬dom之后,后面的問題就開始來考我了。

面:假設現在有1000條數據的長列表,說下不用分頁你怎么優化加載?

不使用分頁,我能想到的自然就是下拉預加載了,比如首先加載10條數據,用戶下拉滾動條快到地步時預加載后10條。

面:你這樣做的話,就是一邊下拉一邊加載,也行,那如果我要一開始拉到滾動條中間位置,直接看到500左右的數據你怎么辦?

我大致想了想,前面的方案其實是沒有一開始展示總高度的,現在要一開始拉到中間位置,自然要把總高度一開始就計算出來。我就說假設每條數據渲染出來都有固定高度,我先計算出1000條數據需要的總高度,然后根據你拉到中間位置,我是可以獲取滾動條距離頂端的高度的,這樣我就能計算出需要展示到第幾百條數據了。

面:這樣做是可以,但是你現在還是渲染出了500條數據,dom也還是很多,有沒有辦法再優化,給你點提示,回收dom。

問到這我就懵逼了,如果我把前面的數據,也就是超出視窗的數據回收,是可以保證視窗內只展示20條數據,那如果我回滾怎么辦,我還得把現在的dom回收掉,不斷去取之前的數據再渲染,這操作dom也太復雜了。然后面試官又對我說,回收dom也是我給你留的坑,你前面說了得計算總高度,一旦dom回收,頁面高度也會坍塌,所以想來想去沒有很好的思路。

面試官笑了笑,說這個其實可以用虛擬dom來做,所以到這我算明白面試官用意,給一個虛擬dom實際場景,在我未掌握該知識的情況下,考我如何用已知知識解決這個問題,第二給我引出虛擬dom的實用性,所以整體我覺得這樣問真的是非常有價值的。

在后面的講解中,我大致理解的做法是這樣,當然不一定准確:

面試官的意思是,將我們的瀏覽器視窗理解成一個畫板,隨着下拉,從虛擬dom中取到一幅幅畫,貼在我們的畫板上,由於是絕對定位貼上去的,脫離了文檔流,所以不存在高度坍塌的問題;總之到這我就是驚了!

面:你怎么學習一個新知識?

我的學習習慣是先通讀文檔,比如vue,我先把整體知識框架搭建起來,這樣好處是能在深入學習之前就知道部分知識的關聯性,整體架構建好了,自然可以根據前輩的經驗,對於重點難點進行深入學習。學習對我而言,最重要的是避免只見樹木不見森林。

面:你怎么平衡知識的新與舊?

我覺得新與舊是一個相對的概念,無法輕易下結論誰好誰壞。舊的東西自然更穩定性,風險性要小,但是思想上可能不如新知識更具便捷性與創新,但也不提倡死板守舊,新的思想總是可以接納的。所以以項目重構而言,還是得考慮成本,風險等多方面因素。

面:一個樹形結構數據,不用遞歸,如何用遍歷去訪問它?

因為說到樹本能會想到遞歸吧,大致給個類似的題目大家看看,求如下數據value的和(題目來源在Javascript中,如何才能不使用遞歸來遍歷一個樹狀結構?):

var nodes = {
    value: 1,
    children: [{
            value: 2,
            children: [{
                    value: 4,
                    children: []
                },
                {
                    value: 3,
                    children: []
                },
            ]
        },
        {
            value: 5,
            children: []
        },
    ]
};

如果用遞歸,就是判斷nodes的children還有沒有子元素,有就繼續遞歸調用自身方法

function sum(nodes) {
    if (nodes.children.length === 0) {
        return nodes.value;
    }
    return nodes.children.reduce((pre, cur) => {
        return pre + sum(cur);
    }, nodes.value)
};

如果不准用遞歸,就得借用其它數據結構,比如隊列(先進先出):

function bfs(nodes) {
    const queue = []
    let sum = 0
    queue.push(nodes)
    while (queue.length) {
        const curNode = queue.pop();
        sum += curNode.value;
        curNode.children.forEach(ele => queue.push(ele));
    };
    return sum;
};

當然這不是我答得,只是給出了一個類似的題目,我算法還是小弱雞。

大致到這,面試就結束了,因為跟面試官聊得還可以,果不其然,第二天收到了復試邀請,在下周二,說實話吧....初面就這么深入,復試是技術總監面,我感覺有點懸,具體面了再說。

肆 ❀ 逃離湖泊投身大海的魚

說下這周面試的感受,我大概就是逃離湖泊投身大海的魚,以前在上家公司,同事覺得我見多識廣,博客園朋友覺得我多厲害,其實幾番面試下來,我自己深知自己與大佬之間的差距,雖然一開始我就不覺得自己有啥厲害的。技術深度,解決問題的能力,軟件設計等等,但這些都不是一時半會能培養起來的,仍需要工作的積累,這也是我為何對於下家公司技術團隊比較看重的原因。

每天壓力還是很大,面試就像一場考試,不管考得好不好,考完了總是覺得松了口氣,像是可以逃避了一樣,可是終究逃不掉,我還是得繼續安排之后的面試,以及不斷的面試。而回想當初離職的決定,我現在反而覺得更正確了,一開始就知道這次會很難,再難這次也要挺過去。

這篇文章花了我一個周末的時間(昨天寫到了凌晨2點...),寫到這居然已經有九千字了,大概是我所有博客里最長的一篇了。我也希望能盡快找到滿意的工作,結束這個系列的更新,畢竟誰又願意頂着壓力天天寫面試分享呢,真正的難受也只有自己心里清楚。

但不管怎么說,我還是會堅持,有面試就一定會總結,只要自己不認輸,那我永遠就沒有輸,請繼續加油!本文結束。

伍 ❀ 參考

from memory cache與from disk cache

徹底弄懂:0.1+0.2 != 0.3

為什么0.1+0.2不等於0.3

JavaScript 浮點數運算的精度問題

為什么0.1+0.2不等於0.3?原來編程語言是這么算的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM