【面試說】一年半前端 Bigo 一二三 面

前言

筆者其實是三月份就面的 Bigo,當時工作經驗算一年半多。之所以現在才發,其實是之前雖然總結了,但多半是自己總結歸納復盤用,有點粗糙,現在重新整理,希望對大家有所幫助

一面

說說 Javascript 的數據類型

最新的 ECMAScript標準 定義了 8 種數據類型

原始數據類型:Boolean、Null、Undefined、Number、BigInt、String、Symbol

引用類型:對象(Object)。其中對象類型包括:數組(Array)、函數(Function)、還有兩個特殊的對象:正則(RegExp)和日期(Date

加分項:BigIntSymbol 類型

BigInt 是一種數字類型的數據,它可以表示任意精度格式的整數。由于 Number 類型的局限性。Number 類型的局限性(JavaScript 中的 Number 是雙精度浮點型,這意味著精度有限,如下所示)

const max = Number.MAX_SAFE_INTEGER; // 9007199254740991
max + 1 // 9007199254740992
max + 2 // 9007199254740992

注意 max + 1 === max + 2,這是不對的

BigInt 就是解決此類問題

Symbol 類型的使用場景

Symbol: 表示獨一無二的值,通過 Symbol 函數生成,接收一個字符串作為參數,表示對 Symbol 實例的描述,主要是為了在控制臺顯示

應用場景:Symbol 的目的就是為了實現一個唯一不重復不可變的值,任何一個 Symbol 都是唯一的,不會和其他任何 Symbol 相等

  • 對象中保證不同的屬性名
    • 注意:使用 Symbol 值定義屬性的時候,必須放在方括號中
    • 讀取的時候也是不能使用點運算符
  • 定義一組常量,保證這組常量都是不相等的
  • 使用 Symbol 定義類的私有屬性/方法
const bar = Symbol('bar');
const snaf = Symbol('snaf');

export default class myClass{

  // 公有方法
  foo(baz) {
    this[bar](baz);
  }

  // 私有方法
  [bar](baz) {
    return this[snaf] = baz; //私有屬性
  }

  // ...
};
  • Vue 中的 project 和 inject

其他應該留意的知識點:

  • 注意屬性名的遍歷

    • 遍歷對象的時候,該屬性不會出現在 for...in...、for...of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回
    • 可以通過 Object. getOwnPropertySymbols()
  • Symbol.hasInstance

    • 指向一個內部方法。當其他對象使用 instanceof 運算符,判斷是否為該對象的實例的時候,會調用這個方法
    • 比如,foo instanceof Foo在語言內部,實際調用的是Foo[Symbol.hasInstance](foo),有點類似劫持了 instanceof 方法
class MyClass {
  [Symbol.hasInstance](foo) {
    return foo instanceof Array;
  }
}
[1, 2, 3] instanceof new MyClass() // true

nullundefined 的區別

null 類型代表著空值,代表著一個空指針對象,typeof null 會是得到 'object' 所以可以認為它是一個特殊的對象值。undefined 當你聲明一個變量未初始化的時候,得到的就是 undefined

  • typeof 的值不一樣
console.log(typeof undefined); //undefined
console.log(typeof null); //object
  • 轉為數值時,值不一樣
console.log(Number(undefined)); //NaN
console.log(undefined + 10);//NaN
console.log(Number(null)); //0
console.log(null + 10); //10
  • === 運算符可區分 nullundefined
  • null 使用的場景
    • 作為對象原型鏈的終點
      Object.getPrototypeOf(Object.prototype) // null
  • undefined 的典型用法 【變量,函數參數,函數返回,對象屬性】

常見的頁面性能優化

HTTP 上有哪些優化手段

重排和重繪的概念,以及如何避免重排和重繪

TCP 三次握手和 TCP 四次握手的區別

關于TCP的握手機制,一定不要死記硬背,要理解為什么這么設計,也就很容易記住了

三次握手:

  • 在客戶端和服務器之間建立正常的TCP網絡連接時,客戶端首先會發出一個 SYN 消息,服務器使用 SYN+ACK 應答表示已經接收到這個消息,最后客戶端再以 ACK 消息響應。這樣在客戶端和服務器之間才能建立起可靠的 TCP 連接,數據才可以在客戶端和服務器之間傳遞

  • 建立連接時,客戶端發送 SYN 包到服務器,等待服務器響應。(SYN 同步序列編號,是建立連接時使用的握手信號)

  • 服務器收到 SYN 包,使用 ACK 包進行確認應答,同時自己也會發送一個 SYN 包,即發送 SYN+ACK 包。
    客戶端收到服務器的 SYN 包,向服務器發送確認包 ACK。此包發送完畢,代表 TCP 連接完成,完成了三次握手

四次揮手:四次揮手是釋放 TCP 連接的握手過程

  • 客戶端向服務端發送釋放連接報文 FIN,等待服務端確認,并停止發送數據
  • 服務器收到連接釋放請求后,發送 ACK 包表示確認。(此狀態下,表示客戶端到服務器的連接已經釋放,不再接受客戶端發的數據了,但是服務器要是還發送數據,客戶端依然接收)
  • 服務器將最后的數據發送完畢后,就向客戶端發送連接釋放報文 FIN,等待客戶端確認。
  • 客戶端收到服務器連接釋放報文后,發出 ACK 包表示確認。此時客戶端會進入 TIME_WAIT 狀態,該狀態將持續 2MSL(最大報文段生存時間,指報文段在網絡中生存的時間,超時將被拋棄)時間,若該時間段內沒有服務器重發請求的話,就進入關閉狀態,當服務端接收到 ACK 應答后,立即進入關閉狀態

[圖片上傳失敗...(image-557c6c-1601881810112)]

webpack 性能優化怎么做的?

小程序的數據更新是怎樣的?

小程序有哪些線程?

[圖片上傳失敗...(image-7bc44e-1601881810112)]

  • 小程序的渲染層和邏輯層分別由 2 個線程管理:渲染層的界面使用了 WebView 進行渲染,邏輯層采用 JsCore 線程運行 JS 腳本
  • 邏輯層:創建一個單獨的線程去執行 JavaScript,在這個環境下執行的都是有關小程序業務邏輯的代碼,由于 js 不跑在 WebView 里,就不能直接操縱 DOM 和 BOM,這就是小程序沒有 window 全局變量的原因
  • 渲染層:界面渲染相關的任務全都在 WebView 線程里執行,通過邏輯層代碼去控制渲染哪些界面。一個小程序存在多個界面,所以渲染層存在多個 WebView 線程
  • 雙線程通信【Virtual DOM 相信大家都已有了解,大概是這么個過程:用JS對象模擬DOM樹 -> 比較兩棵虛擬DOM樹的差異 -> 把差異應用到真正的DOM樹上。】
1、在渲染層把 WXML 轉化成對應的 JS 對象

2、在邏輯層發生數據變更的時候,通過宿主環境提供的 setData 方法把數據從邏輯層傳遞到 Native,再轉發到渲染層

3、經過對比前后差異,把差異應用在原來的 DOM 樹上,更新界面

[圖片上傳失敗...(image-7c1072-1601881810112)]

小程序多次設置很多數據的時候會對性能產生很大的影響么?怎么優化

有,可以統一一次設置,多次盡量最后一次設置

Vue 2.x 的實現原理?

回答了雙向數據綁定的相關原理

Vue 的 diff 算法

Vue 的 compile 過程

  • 主要是三個過程 parseoptimizegenerate
  • compile 的作用是解析模板,生成渲染模板的 render。而 render 的作用,也是為了生成跟模板節點一一對應的 Vnode
  • parse: 接收 template 原始模板,按照模板的節點 和數據 生成對應的 ast【通過大量的正則匹配去實現對字符串的解析】
  • Optimize:遍歷遞歸每一個ast節點,標記靜態的節點(沒有綁定任何動態數據),這樣就知道那部分不會變化,于是在頁面需要更新時,減少去比對這部分DOM。從而達到性能優化的目的。【為什么要有優化過程,因為我們知道 Vue 是數據驅動,是響應式的,但是我們的模板并不是所有數據都是響應式的,也有很多數據是首次渲染后就永遠不會變化的,那么這部分數據生成的 DOM 也不會變化,我們可以在 patch 的過程跳過對他們的比對。】
  • Generate:把前兩步生成完善的 ast 組裝成 render 字符串(這個 render 變成函數后是可執行的函數,不過現在是字符串的形態,后面會轉成函數)

Vuex簡單的原理實現【同時考察了發布訂閱的模式】

參考:面試題:談談你對對vuex的理解

移動端有哪些兼容的場景【重點回顧】

<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
  • 上下拉動滾動條時卡頓、慢。Android3+和iOSi5+支持CSS3的新屬性為overflow-scrolling
  body {
    -webkit-overflow-scrolling:touch;
    overflow-scrolling:touch;
}
 - ios和android下觸摸元素時出現半透明灰色遮罩
-webkit-tap-highlight-color:rgba(255,255,255,0);
  • click 的 300ms 延遲問題

問題:在移動端中,click事件是生效的,但是,點擊之后會有300ms的延遲響應

原因:safari是最早做出這個機制的,因為在移動端里,瀏覽器需要等待一段時間來判斷此次用戶操作是單擊還是雙擊,所以就有click 300ms 的延遲機制

方案一:禁用縮放

HTML文檔頭部包含如下 meta 標簽時:表明這個頁面是不可縮放的,那雙擊縮放的功能就沒有意義了,此時瀏覽器可以禁用默認的雙擊縮放行為并且去掉 300ms 的點擊延遲

<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">

方案二:更改默認的視口寬度

<meta name="viewport" content="width=device-width">

如果設置了上述meta標簽,那瀏覽器就可以認為該網站已經對移動端做過了適配和優化,就無需雙擊縮放操作了
??這個方案相比方案一的好處在于,它沒有完全禁用縮放,而只是禁用了瀏覽器默認的雙擊縮放行為,但用戶仍然可以通過雙指縮放操作來縮放頁面。

方案三:引入 fastclick 庫來解決

FastClick 的實現原理是在檢測到 touchend 事件的時候,會通過 DOM 自定義事件立即出發模擬一個click事件,并把瀏覽器在300ms之后的click事件阻止掉。

參考:http://www.lxweimin.com/p/b5c103a9bed0

  • 水平居中和垂直居中

  • node有使用過么

二面

HTTP 中的 content-encoding

Content-Encoding 是一個實體消息首部,用于對特定媒體類型的數據進行壓縮。當這個首部出現的時候,它的值表示消息主體進行了何種方式的內容編碼轉換。這個消息首部用來告知客戶端應該怎樣解碼才能獲取在 Content-Type 中標示的媒體類型內容。

Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate
Content-Encoding: identity
Content-Encoding: br

參考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Encoding

HTTP 中的長連接

HTTP 協議采用“請求-應答”模式,當使用普通模式,即非 KeepAlive 模式時,每個請求/應答客戶和服務器都要新建一個連接,完成 之后立即斷開連接(HTTP 協議為無連接的協議);當使用 Keep-Alive 模式(又稱持久連接、連接重用)時,Keep-Alive 功能使客戶端到服 務器端的連接持續有效,當出現對服務器的后繼請求時,Keep-Alive 功能避免了建立或者重新建立連接

http 1.0 中默認是關閉的,需要在 http 頭加入 "Connection: Keep-Alive",才能啟用 Keep-Alive;http 1.1 中默認啟用 Keep-Alive,如果加入 "Connection: close ",才關閉。目前大部分瀏覽器都是用 http1.1 協議,也就是說默認都會發起 Keep-Alive 的連接請求了,所以是否能完成一個完整的 Keep- Alive 連接就看服務器設置情況

參考:https://blog.csdn.net/gt11799/article/details/41147933
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Keep-Alive

說下 JS 中的事件循環

強緩存和協商緩存

啟發緩存有了解過么

  • 沒有任何關于緩存的字段 —— 不設置任何緩存策略
  • 常會取響應頭中的 Date 減去 Last-Modified 值的 10% 作為緩存時間

參考:

V8 中的垃圾回收機制

參考:【Web技術】737- 深入理解 Chrome V8垃圾回收機制

node 的全局變量有哪些

JavaScript 中有一個特殊的對象,稱為全局對象(Global Object),它及其所有屬性都可以在程序的任何地方訪問,即全局變量

在瀏覽器 JavaScript 中,通常 window 是全局對象, 而 Node.js 中的全局對象是 global,所有全局變量(除了 global 本身以外)都是 global 對象的屬性。

在 Node.js 我們可以直接訪問到 global 的屬性,而不需要在應用中包含它。
global,process,__filename,__dirname

參考:Node.js 全局對象

node 了解程度

ES6 有了解哪些?

set 和 map 有了解么?

map 的實現原理是什么?

Map 利用鏈表,hash 的思想來實現。

首先,Map可以實現刪除,而且刪除的數據可以是中間的值。而鏈表的優勢就是在中間的任意位置添加,刪除元素都非常快,不需要移動其他元素,直接改變指針的指向就可以。而在存儲數據很多的情況下,會導致鏈條過長,導致查找效率慢,所以我們可以創建一個桶(存儲對象的容器),根據 hash(把散列的值通過算法變成固定的某值)來平局分配數據,防止鏈條過長。

參考:

為什么要想著離職呢?

算法題

輸入[1,3,1,3,2],輸出數組中唯一一個只存在一項的值,比如如上就是 2

三面

談談你的項目【其中針對項目進行了提問】

說說 webpack 打包優化

從一個數組中拿到前三個最小的值

一道編程題

[1,2,3,1,2,4,1,3,2,1] [1,2] [3,4,5] =>[3,4,5,3,3,4,5,4,1,3,2,1]

說明:第一個輸入是原始數組,第二個輸入是一個條件:要在原始數組中的連續數組,第三個輸入是要替換掉原數組符合參數二條件的數據

能夠使用的api:
1. 數組的長度獲取。
2. 數組某個下標對應的數字。
3. 往數組里push元素。

總結

歸納總結了 Bigo 一二三面的知識,有一些問題總結回答建議,有一些沒有,希望對大家有幫助

參考

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容