“寒冬中”三年前端社招面試經驗

op_yolo發表於2019-04-19

前言:16 年畢業的渣本程式設計師,畢業後一直在上海某公司工作,小組氛圍以及同事都非常 nice,但是業務線發展不好,年後回來後被砍了,不想內部轉崗到其他部門,所以加入了找工作的大潮。這次的找工作經歷對我來說很重要,它讓我在準備的過程中突然對很多技術問題有所覺悟,想記錄一下這次的經驗。

基本都是在 Boss 直聘加內推 ( 內推真的會比較靠譜,可以提前知道訊息並且避免去邊緣部門 ) 上投的,也沒投幾家,一開始就是奔著大廠去的,現在的公司不算大廠並且是按照業務線分組的,所以我們小組幾個人開發一款產品,前端也一直只有我一個人在負責,所以一直想去大廠試試。

大概面了 xxxxxxxxxxx(面試公司已刪,去哪家都是搬磚,差不了多少的),也是從一開始面試講話都有點不太自信,到後面有底氣去跟面試官扯皮子了,心態變化了很多。

忘了準備多久,目前的公司其實不加班,但是我都是晚上留到八九點,看書刷題,之前一直想看的劍指 offer 居然也看完了,不懂的會跟著刷,重新開了 LeetCode 中國區的賬戶,刷了 10% 的題目,達到了一開始是對演算法沒有思路到不再害怕演算法知道可以從哪裡入手的水平,很多公司面試演算法其實沒要求那麼高特別是前端,不過也要對自己要求高一點。

因為剛剛旅遊了一趟回來,對具體哪家公司的面試題目不太分得清了,以下都是我的面試內容,希望能對其他人有所幫助:

css

1. 三欄佈局

  • float
  • bfc (set middle area overflow is hidden)
  • position: absolute
  • 雙飛翼佈局
  • flex
  • table

2. 垂直居中

個人感覺這個問很多,我一般就是答以下幾種:

  • line-height: height 有被問到該值是不是等於高度設定的值,這個沒有答好,回來測試發現是跟盒模型相關的,需要是 computed height
  • absolute + transform 居中為什麼要使用 transform(為什麼不使用marginLeft / Top),這是一道重繪重排的問題。
  • flex + align-items: center 我會對 flex 容器以及 flex 專案的每個 css 屬性都瞭解一遍,並且寫了一些小 demo。

3. 盒模型

4. BFC

  • 概念
  • 如何觸發
  • 怎麼應用

5. CSS 前處理器

一般回答 變數 / 巢狀 / 自動字首 / 條件語句 / 迴圈語句

我是一直很欣賞張鑫旭大神對 CSS 研究到非常透徹的境界,但是總結下來,對 CSS 一般不會考得很深,業界對 CSS 的專注度其實不夠,包括我個人也是沒投入很多時間精力在 CSS 上,如果有更深入的理解當然是更好的。

JS

1. 原型

其實之前剛畢業的時候就在啃高階程式設計,三年後還是在考這個點。

  • 閉包 / 作用域 / this 指向
  • 實現 繼承
  • es5 實現 class
  • es5 實現 new

2. var let const

let/const 也存在變數宣告提升,只是沒有初始化分配記憶體。 一個變數有三個操作,宣告(提到作用域頂部),初始化(賦預設值),賦值(繼續賦值)。

  • var 是一開始變數宣告提升,然後初始化成 undefined,程式碼執行到那行的時候賦值。
  • let 是一開始變數宣告提升,然後沒有初始化分配記憶體,程式碼執行到那行初始化,之後對變數繼續操作是賦值。因為沒有初始化分配記憶體,所以會報錯,這是暫時性死區。
  • const 是隻有宣告和初始化,沒有賦值操作,所以不可變。

const 只是保證了指向的記憶體地址不變,而不是內部資料結構不變。確保不會被其他型別的值所替代。

3. 實現 promise

面 tx 的時候有讓我手寫實現 promise,因為有看過一點 bluebird 的原始碼,所以對我來說還好。寫了一半就讓我停下來,我一般會邊寫邊講解,一上來先把框架搭好,例如

class Promise {
    constructor(executor) {
        // 設定屬性 status value resolveCbs rejectCbs
    }
    then(onResolved, onRejected) {}
    catch (cb) {
        return this.then(null, cb)
    }
}
複製程式碼

然後再慢慢填充,這種做法會一上來讓人感覺你是有思路的,而且瞭解 promise 的語法。

4. promise 鏈式

例如 promises = [],實現必須上一個非同步完成後再去跑下一個任務。我是寫出兩種方案:

// 1.
const template = Promise.resolve();
promises.forEach((p) => {
    template = template.then(p)
})
// 2. 使用 await 
複製程式碼

個人感覺對 promise、async/await 都問比較多,包括比較火的問列印順序那種題還有捕獲異常的問題我也遇到過,只要對語法非常熟悉加上稍微瞭解實現細節都是沒問題。

5. 實現 bind

6. 實現事件系統 eventEmitter

跟 promise class 一樣,先搭建一個框架:

class EventEmitter {
    constructor() {
        this.events = {}
    }
    emit (eventName, args) {}
    on (eventName, callback) {}
    off (eventName, callback?) {}
}
複製程式碼

之前有寫過事件系統,但是沒有考慮 once 之類的 method,也是面試官說了需求再一點點補充的。

7. 手寫 Proxy / Object.defineProperty

8. 事件委託

9. Event Loop

JS 執行是單執行緒的,它是基於事件迴圈的。事件迴圈大致分為以下幾個步驟:

(1)所有同步任務都在主執行緒上執行,形成一個執行棧。

(2)主執行緒之外,還存在一個"任務佇列"。只要非同步任務有了執行結果,就在"任務佇列"之中放置一個事件。

(3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務佇列",看看裡面有哪些事件。那些對應的非同步任務,於是結束等待狀態,進入執行棧,開始執行。

(4)主執行緒不斷重複上面的第三步。

event loop 基本每次都會被問到,一般就是說微任務、巨集任務,怎麼樣的執行過程,以上是比較書面一點的回答,我自己也沒記得。

10. Webpack

  • loader plugin 的區別,一開始被問到還有點驚訝,不同作用的功能被問到一起。
  • tree-shaking 的工作原理
  • code splitting用的是什麼外掛
  • 如何提高 webpack 構件速度的
    • 利用 DllPlugin 預編譯資源模組
    • 使用 Happypack 加速程式碼構建

我寫過很多小專案,所以配過很多次 webpack,從 V2 到 V4,不過 webpack 一般沒有問很多。

11. 前端效能提升

一般我會分為以下幾個方面來回答,一般會引申到網路、快取方面的問題:

server:

  • 使用 cdn
  • 減少不必要的資料返回
  • 使用 gzip
  • 快取 (etag / expires ...)

content:

  • 減少 http 請求 (css sprites / inline image)
  • 不同資源放在不同域下 (http1.1)
  • 延遲載入 / 延遲執行(立即下載,延遲執行[before DOMContentLoaded]defer) / 預載入(preload)
    • async,該布林屬性指示瀏覽器是否在允許的情況下非同步執行該指令碼。該屬性對於內聯指令碼無作用 (即沒有 src 屬性的指令碼)。
    • defer,這個布林屬性被設定用來通知瀏覽器該指令碼將在文件完成解析後,觸發DOMContentLoaded事件前執行。
  • 精簡 HTML 結構
  • 壓縮資源

css:

  • in head
  • 較少的層級(之前被問到過是否有統計過層級多與少對效能的實質影響,實際上我是沒有做過此類研究,所以知道結論而不懂過程還是欠缺的)

js:

  • before
  • 減少 dom 訪問(在 body 內放置的 JS 程式碼是否可以訪問到 body 標籤)

webpack:

  • tree shaking 去除沒有使用的程式碼
  • 提取公共包,有被問到
  • 拆分模組,按需載入
  • 優化圖片,使用 base64 代替小圖
  • file name with hash (etag)

12. Vue

因為我是寫 Vue 居多,所以簡歷上只寫了 Vue 而沒有 react 等其他框架,一般都是被問到 Vue。

  • 父子元件通訊
  • 生命週期
  • 資料響應(資料劫持) 資料響應的實現由兩部分構成: 觀察者( watcher )依賴收集器( Dep ),其核心是 defineProperty這個方法,它重寫屬性的 getset 方法,從而完成監聽資料的改變。一般會要求從解析到收集依賴到通知一套工作原理比較熟悉。我是大概理解,跟著讀了一些原始碼,但是還是沒有講很清楚,遺憾沒有表現好。
  • 虛擬 dom、dom diff
  • nextTick

JS 肯定是重點考察的部分,物件、繼承方面只要讀透高程再寫幾個 demo 掌握細節,es6 我是一直翻阮一峰寫的 ECMAScript 6 入門,Vue 的話首先把官網的內容掌握了,然後再去讀一些部落格或者直接上原始碼也是可以的。

HTTP

1. 跨域

基本都被問同源策略以及引申到跨域來,一般我會說 CORS 以及 jsonp,CORS 會從簡單請求跟非簡單請求區分開,再講 options 請求的意義。

2. HTTP 報文

請求行 + 頭部資訊 + 空白行 + body 有被問到說空白行的意義,我一直以為就是純粹來標識 headers 的結束,但是面試官說不止這個功能,我後面看了HTTP 權威指南 也沒有找到,Stack Overflow 也沒找到。。。希望有人知道可以跟我說一下。不過有可能是我聽錯了題目,畢竟是電話面試。

3. cookie session

一般會問兩者的差別,以及引申到 sessionStorage, localStorage, cookie 區別

4. 從輸入 URL 到頁面載入全過程

一般我會答連結的大部分步驟,按照理解來,這裡面我被問到的點有:

  • 快取,分為強快取、協議快取,一般會問到 304 的表現,以及再引申到 301 302 的區別,我會再說 307 的區別。
  • 三次握手
  • HTTPS 的工作原理
  • CDN 的工作原理,以及重新整理快取的原理。
  • 瀏覽器渲染的步驟
  • 重繪重排的概念,以及最佳實踐。一直都知道應該用 transform 代替 margin,但是一被問原理,就不太清楚,查了資料是對 translate3d 的元素進行 GPU 加速。
  • 會因為 JS 是單執行緒而問到阻塞的問題,引申到 async defer 等屬性。
  • status code 有哪些,我們是嚴格按照 restful 的規範來設計介面,所以這個問題我一直覺得很簡單,但是被問到不少次。我記得趣頭條的筆試就有,我會把用過的按照 2xx(200, 201, 204, 206) 3xx(301, 302, 304, 307) 4xx(400, 401, 403, 405) 5xx(500, 502, 504) 來分類,我偶爾寫寫 rails,所以對對應的名詞都比較熟悉 貼一篇 list of rails status codes
  • DNS 解析過程

5. xss,csrf

  • xss 注入攻擊
    • 轉義
  • csrf (cross site request forgery)
    • Get 請求無副作用
    • cookie httponly
    • cors (origin not *)

我是通過看 這篇文章 對安全有更多瞭解的,推薦一下。

6. sse( server sent event)

因為寫過一個 sse 相關的外掛,所以被問到過,是如何使用以及 EventSource 的 API。

感覺前端對網路、安全方面要求不是很高,沒被問過 HTTP2 或者長連線更多內容,之前看脈脈上一個後端被問從瀏覽器裡訪問一個地址,從網路的 tcp/ip 協議、聊到作業系統 io、記憶體管理、程式管理和檔案管理,再聊到負載均衡、限流演算法、分散式事務,相比之下前端真的簡單很多,不過知識儲備多肯定是有用的。

演算法

演算法一般考得不難,不過基本每一次面試都會考到,我記得被考到演算法題目有:

  • 層次遍歷一棵二叉樹 (這是唯一一道劍指 offer 上的題目了,最簡單的 ? )
  • 字串中找出最長最多重複的子串

想列舉發現很多已經忘了,感覺很少會直接出現劍指 offer 的題目,也不會直接問某排序演算法怎麼寫,這是我個人的體驗,僅供參考。刷題還是很有用的。

Git

  • 基本操作

  • git rebase vs git merge

    • git merge
      • 記錄下合併動作 很多時候這種合併動作是垃圾資訊
      • 不會修改原 commit ID
      • 衝突只解決一次
      • 分支看著不大整潔,但是能看出合併的先後順序
      • 記錄了真實的 commit 情況,包括每個分支的詳情
    • git rebase
      • 改變當前分支 branch out 的位置
      • 得到更簡潔的專案歷史
      • 每個 commit 都需要解決衝突
      • 修改所有 commit ID

    回答時候沒有答出很多,這是後面總結,深刻發現日常做總結的必要性,一直覺得自己是瞭解的,等到總結時候才發現有一些 point 還是不清楚的。

  • 修改 commit message

沒有問很深,只是基礎操作多一點。如果日常是使用 git 開發,一般比較輕鬆應對。


總結:以上都是我的面試題目,並非齊全的面試準備內容,我也遺忘了很多題目,再不寫下來估計忘更多了。一般都是問具體的技術問題加上專案經歷,因為我這邊做的事情是技術多於業務,目前只有我一個人負責全部的前端內容,所以對每個專案都非常熟悉,建議對寫在簡歷上的專案都知根知底,避免出現被問到時候含糊不清的尷尬場景。

至於標題為什麼“寒冬”加上雙引號,我覺得對寒冬的解釋在於個人而非完全是大環境影響,感覺每個公司都挺缺人的,掛了鵝廠後 HR 給我看了面試評價以及又幫我投了其他部門,不過是我在旅遊期間聯絡我的,已經接了 offer 就沒繼續面了。

我這次找工作的體會大致如此,沒有很糟糕沒有很愉快,過程中壓力也是比較大的,但是換工作就是如此的啊,從舒適區跳出來太難了,希望能通過我的經歷給人一點幫助吧。


這算是我寫的第一篇部落格,有收到一些關注,只是因為在 juejin 看了一些面經所以想也寫一篇而已,其實是沒有寫部落格的習慣,所以關注的可以取關。。。交流一些前端技術是歡迎的。

相關文章