1. 程式人生 > 實用技巧 >面試阿里巴巴前端開發工程師電話面試部分

面試阿里巴巴前端開發工程師電話面試部分

原文連結: 掘金文章

筆試部分請翻閱上上篇文章

1. 盒模型

  • 盒模型屬性有:margin、padding、border、content
  • 標準盒模型: width/height => 指的是content部分的寬/高
  • 怪異盒模型(IE瀏覽器)width/height => 指的是 border + padding + content

2. BFC

  • 介紹: 塊格式化上下文
  • 特性(功能):
    • 內部的盒會在垂直方向一個接一個排列
    • 處於同一個BFC中的元素相互影響,可能會發生重疊
    • BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素
    • 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算
  • 觸發 BFC 特性:
    • 浮動元素:floatnone 以外的值
    • 絕對定位元素:position (absolute、fixed)
    • overflow 除了 visible 以外的值 (hidden、auto、scroll)
    • display 的值為 table-cell, table-caption, inline-block, flex, 或者 inline-flex中的其中一個
  • BFC有什麼作用:
    • 避免外邊距合併
    • 防止正常文件流中元素佔據浮動元素位置
    • 消除浮動
    • 實現自適應佈局

3. 你工作開發中 ES6 及以上常用特性

  • 注:記些工作中常用的就好, 以下均為粗略的介紹,詳細介紹請自行百度
  • 一總結嚇自己一跳,有好多方法其實我們都在用,但是不知道是Es6 及以上的功能;ES7以上有相容性問題,要注意
  • 有點亂, ES6-ES11之間相互穿插了一些功能
  • ES6 詳情 菜鳥教程很完善的文件 https://www.runoob.com/w3cnote/es6-tutorial.html
    • letconst:塊級作用域
    • 模板字串:${}
    • 解構賦值
    • Symbol:新的原始資料型別 Symbol ,表示獨一無二的值,最大的用法是用來定義物件的唯一屬性名
    • Map:Map 物件儲存鍵值對。任何值(物件或者原始值) 都可以作為一個鍵或一個值。
    • Set:物件允許你儲存任何型別的唯一值,無論是原始值或者是物件引用。
    • Proxy:可以對目標物件的讀取、函式呼叫等操作進行攔截,它不直接操作物件,而是通過代理模式,通過物件的代理物件進行操作;vue3.0重要方法
    • Reflect:可以用於獲取目標物件的行為,它與 Object 類似,但是更易讀,為操作物件提供了一種更優雅的方式。它的方法與 Proxy 是對應的
    • 字串拓展的方法:
      • includes():返回布林值,判斷是否找到引數字串;
      • startsWith():返回布林值,判斷引數字串是否在原字串的頭部;
      • endsWith():返回布林值,判斷引數字串是否在原字串的尾部。
      • repeat():返回新的字串,表示將字串重複指定次數返回。
      • padStart():前置填充字串; 經典常用 --> 前置補0。
      • padEnd():後置填充字串; 經典常用 --> 後置補0 。
    • Number 物件新方法
      • Number.isFinite(): 檢查一個數值是否為有限的( finite ),即不是 Infinity
      • Number.parseInt(): 將給定字串轉化為指定進位制的整數
    • Math 物件的擴充套件: ... 一大堆,請檢視文件
    • 物件的新方法:
      • Object.assign(target, source_1, ···): 將源物件的所有可列舉屬性複製到目標物件中
      • Object.is(value1, value2):比較兩個值是否嚴格相等
    • 陣列的拓展:
      • Array.of():將引數中所有值作為元素形成陣列。
      • Array.from(): 將類陣列物件或可迭代物件轉化為陣列。
      • find():查詢陣列中符合條件的元素,若有多個符合條件的元素,則返回第一個元素
      • findIndex():查詢陣列中符合條件的元素索引,若有多個符合條件的元素,則返回第一個元素索引。
      • fill():將一定範圍索引的陣列元素內容填充為單個指定的值。
      • copyWithin():將一定範圍索引的陣列元素修改為此陣列另一指定範圍索引的元素。
      • entries():遍歷鍵值對。
      • keys():遍歷鍵名。
      • values():遍歷鍵值。
      • includes():陣列是否包含指定值。
    • 函式擴充套件
      • 箭頭函式
      • 預設引數
      • 不定引數
    • for...of迴圈:迭代常規的資料型別,如 Array 、 String 、 Map 和 Set 等等(有點強大)
    • Class 類的定義
    • extends 繼承
    • 匯出(export)、匯入(import)兩個模組
    • Promise 物件非同步操作
      • pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。除了非同步操作的結果,任何其他操作都無法改變這個狀態
      • pending 變為 fulfilled 和從 pending 變為 rejected 的狀態改變。只要處於 fulfilledrejected ,狀態就不會再變了即 resolved(已定型)
    • Generator 函式:可以通過 yield 關鍵字,把函式的執行流掛起,為改變執行流程提供了可能,從而為非同步程式設計提供解決方案
  • ES7
    • Array.prototype.includes:表示某個陣列是否包含給定的值,與字串的includes方法類似
    • 指數運算子(冪運算):
  • ES8
    • Async/Await:非同步函式有效避免回撥地獄
    • Object.values():遍歷物件的屬性值,無需使用使用屬性名
    • Object.entries():遍歷物件的屬性名和屬性值
    • Object.getOwnPropertyDescriptors():獲取一個物件的所有自身屬性的描述符。
  • ES9
    • 非同步迭代:iterator(迭代器)除了next()方法返回一個Promise。因此await可以和for...of迴圈一起使用,以序列的方式執行非同步操作
    • Promise.finally(): 返回一個Promise,無論結果是fulfilled或者是rejected,在執行then()catch()後,都會執行finally指定的回撥函式
    • Rest/Spread 屬性
    • 正則表示式命名捕獲組
    • 正則表示式反向斷言
    • 正則表示式Unicode屬性轉義
  • ES10
    • Array.prototype flat, flatMap: 扁平化陣列
    • Object.fromEntries:它可以將鍵值對陣列還原成物件結構, 相對應 Es6Object.entries方法 遍歷物件的屬性名和屬性值
    • String.protope.{trimstart, trimEnd}:可以分別去除頭和尾上的空格、換行符
    • Symbol.protoype.description:獲取Symbol型別資料的描述資訊
    • 可選的catch引數
    • Function.prototype.toString:之前函式物件呼叫toString方法,會將它定義過程中的註釋等資訊去掉,現在會原樣進行輸出
    • Array.prototype.sort():穩定的陣列排序; V8的先前實現,對包含10個以上項的陣列使用了不穩定的快速排序演算法(快排和插入排序演算法,預設是將陣列元素轉為字串,然後根據Unicode字符集編號的大小排序)。
  • ES11
    • BigInt資料型別: 表示一個任意精度的整數,可以表示超長資料,可以超出2的53次方
    • 私有變數: 通過在變數或函式前面新增一個雜湊符號#,可以將它們設為私有屬性,只在類內部可用
    • Promise.allSettled: 其引數接受一個Promise的陣列, 返回一個新的Promise, 其不會進行短路, 當Promise全部處理完成後我們可以拿到每個Promise的狀態, 而不管其是否處理成功;Promise.all\Promise.rae任何一個失敗都會造成短路
    • 可選鏈操作符 ?.
    • 空值合併運算子 ??
    • import支援動態載入模組,載入模組成功以後,這個模組會作為一個物件,當作then回撥的引數。因此,可以使用物件解構賦值的語法,獲取輸出介面
    • globalThis:一種標準化的方式去訪問全域性物件,這時候可以在任意上下文中獲取全域性物件自身,並且不用擔心環境的問題
    • String.protype.matchAll(): 返回所有與正則表示式匹配字串的結果的迭代器,包括捕獲組

4. mapobject 的區別

  • key 必須是簡單資料型別(整數,字串或者是 symbol),但一個 Map 的鍵可以是任意資料型別任意值。
  • Map 中的鍵值是有序的(FIFO 原則),而新增到物件中的鍵則沒有這一特性。
  • Map 的鍵值對個數可以從 size 屬性獲取,而 Object 的鍵值對個數只能手動計算。
  • new Map()set、get方法
  • Object 都有自己的原型,原型鏈上的鍵名有可能和你自己在物件上的設定的鍵名產生衝突, Map 繼承自 Object 物件。

5. TypescriptJavaScript 的不同, 常用型別有哪些

JavaScript特點、特性:

  • 解釋性指令碼語言(不進行預編譯,跟java一樣);
  • 在html頁面上提供互動行為、既可以寫成單獨的js檔案,也可以嵌入在html中
  • 可跨平臺,因為受到了各種瀏覽器的支援,這使得js可以在各種平臺上執行
  • 作為客戶端指令碼語言,獨立運行於使用者的瀏覽器,不需要伺服器的支援,減少對伺服器的負擔
  • 不安全性,顯然這個特性和上一個特性相關
  • 事件驅動、非同步、動態化,和大部分指令碼語言一樣,型別與值而不是與變數關聯

typescript是微軟開發的用於開發大型應用的程式語言,其為javascript的嚴格超集,並添加了可選的靜態型別和基於類的面向物件程式設計

  • typescript完全相容javascript,且最終編譯成javascript執行
  • typescript有編譯時型別檢查,這為程式的編寫帶來了極大的方便
  • javascript是一門動態語言,而typescript添加了可選的靜態型別
  • typescriptjavascript的基礎上增加了不少特性(型別批註、編譯時型別檢查、型別推斷、介面、列舉、混入、泛型程式設計、名稱空間、元組、類、可選引數、預設引數 .........)
  • ++常用型別有++:7大基本資料型別、any(任意值 --- 頂級型別)、unknown(任意值 --- 頂級型別)、never(永不存在的值的型別)、void (空值)、Tuple (元組)、enum (列舉)、interface介面型別、泛型

6. vuereact 有哪些區別 (自由擴充套件,能擴充套件到很遠)

  • 監聽資料變化的實現原理不同
  • Vue通過 getter/setter以及一些函式的劫持,每個元件都有自己的渲染watcher,它掌管了當前元件的檢視更新,但是並不會掌管 ChildComponent 的更新, 能精確知道資料變化
  • React 在類似的場景下是 自頂向下的進行遞迴更新的;就是說,React 中假如 ChildComponent 裡還有十層巢狀子元素,那麼所有層次都會遞迴的重新render(在不進行手動優化的情況下),在事務結束時觸發;更新是一個同步的過程,會影響渲染,造成卡頓,這是效能上的災難。
  • React 因為他們遵從Immutable的設計思想,永遠不在原物件上修改屬性,由於沒有響應式的收集依賴,React 只能遞迴的把所有子元件都重新 render一遍,然後再通過 diff演算法 決定要更新哪部分的檢視,這個遞迴的過程叫做 reconciler;
  • React在初始化的時候,會把真實的dom轉化成虛擬的dom,vnodefiber物件節點;(因此,React 創造了Fiber,創造了非同步渲染,其實本質上是彌補被自己搞砸了的效能)
  • React 預設通過比較引用的方式(diff)進行的,如果不優化可能導致大量不必要的VDOM的重新渲染;原因:Vue使用的是可變資料,而React更強調資料的不可變,兩者沒有好壞之分,Vue更加簡單,而React構建大型應用的時候更加有利
  • Vue可以做到更小粒度的更新,而react做不到,這是由資料驅動決定的,vue的底層diff演算法參考linux的檔案比較演算法,在效率上比reactdiff更好一點,但是react實現了requsetIdleCallback,讓計算不影響渲染。更加流暢
  • 資料流的不同:vue 使用 v-model 實現雙向資料繫結, react 需手動呼叫 setState 方法實現
  • HoCmixins: vue 使用mixin實現混合, reactmixins 轉向了HoC(高階元件)(覺得mixins 覺得這種方式對元件侵入太強會導致很多問題)
  • 模板渲染方式的不同:
  • React是通過JSX渲染模板都,通過原生JS實現模板中的常見語法,比如插值,條件,迴圈等,都是通過JS語法實現的,更加純粹更加原生;
  • Vue是通過一種拓展的HTML語法進行渲染,通過指令來實現各種js邏輯,有些獨特,但會把HTML弄得很亂
  • 渲染過程不同:
  • Vue可以更快地計算出Virtual DOM的差異,這是由於它在渲染過程中,會跟蹤每一個元件的依賴關係,不需要重新渲染整個元件樹
  • React在應用的狀態被改變時,全部子元件都會重新渲染。通過shouldComponentUpdate這個生命週期方法可以進行控制,但Vue將此視為預設的優化
  • 如果應用中互動複雜,需要處理大量的UI變化,那麼使用Virtual DOM是一個好主意。如果更新元素並不頻繁,那麼Virtual DOM並不一定適用,效能很可能還不如直接操控DOM
  • 框架本質不同: Vue本質是MVVM框架,由MVC發展而來; React是前端元件化框架,由後端元件化發展而來
  • 狀態管理VuexRedux的區別:
  • Redux使用的是不可變資料;每一個元件都需要顯示的用connect把需要的propsdispatch連線起來;只能進行dispatch,不能直接呼叫reducer進行修改
  • Vuex的資料是可變的;$store被直接注入到了元件例項中,因此可以比較靈活的使用dispatch、commit提交更新,可通過mapState、mapActions、mapGetters、mapMutations功能函式或者直接通過this.$store來讀取資料和操作函式

7. vue3.0 新特性,和vue2.0的主要區別

  • 開發構建工具的重構 vite

Vue團隊也推出了自己的開發構建工具Vite,可以在一定程度上取代vue-cliwebpack-dev-server的功能;Vite在開發環境下基於瀏覽器原生 ES Modules 開發,在生產環境下基於 Rollup 打包; Vite主要有以下特性:

  • 快速的冷啟動
  • 即時的模組熱更新
  • 真正的按需編譯
  • 重構了Virtual DOM

Vue2.x版本會遍歷 template 模板中的所有內容,並根據這些標籤生成對應的虛擬DOM,當有內容改變時,遍歷虛擬DOMdiff找到對應的標籤元素所對應的DOM節點,實現雙向資料繫結;但是對於那些純靜態的節點進行diff其實是比較浪費資源的,當節點的數量很少時,表現並不明顯,但是一旦節點的數量過大,在效能上就會慢很多; vue3.0 在此基礎上優化有:

  • 標記靜態內容,並區分動態內容
  • 更新時只diff動態的部分
  • 基於Proxy的響應式物件,替換了Object.defineProperty()
  • Proxy可以直接監聽物件和陣列(而非屬性)的變化,並且有多達13種攔截方法。並且作為新標準將受到瀏覽器廠商重點持續的效能優化
  • Proxy 返回的是一個新物件,我們可以只操作新的物件達到目的,而Object.defineProperty只能遍歷物件屬性直接修改;
  • Object.defineProperty無法監聽變異陣列(會修改原來陣列的方法:push、pop、shift、unshift、splice、sort、reverse等,是無法觸發 set 的)的變化, 需要單獨處理; 必須遍歷物件的每個屬性並新增劫持;必須深層遍歷巢狀的物件,直到把每個物件的每個屬性都呼叫 Object.defineProperty() 為止;
  • Proxy只會代理物件的第一層,Vue3是怎樣處理這個問題的呢?
    • 判斷當前Reflect.get的返回值是否為Object,如果是則再通過reactive方法做代理, 這樣就實現了深度觀測。
    • 監測陣列的時候可能觸發多次get/set,那麼如何防止觸發多次呢?我們可以判斷key是否為當前被代理物件target自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個條件之一時,才有可能執行trigger
  • composition-api

composition-api(配置式API開發)提供了一種建立響應式物件的方法reactive,選擇性的監聽屬性,這樣就可以不用針對每個屬性來一一進行新增,減少開銷提升效能;

  • Tree shaking支援

移除JavaScript上下文中的未引用程式碼不會被打包;一定程度上減少了資源的大小, 提升了構建、執行速度

  • TypeScript 的支援
  • Vue3中直接採用了typescript來進行重寫,從原始碼層面來提升專案的可維護性
  • Typescript 能夠在開發時及時發現問題,而非執行時,大大的提升了系統的穩定性
  • 靜態型別檢查很大程度的統一了團隊之間的開發習慣,易於專案的維護,提高開發人員的工作效率節約開發成本
  • 更加豐富的型別支援及開發便利
  • 移除的一些API和方法
  • 取消KeyboardEvent.keyCode: 使用別名代替
  • 移除 $on,$off$once方法: EventBus --> mitt方案來代替
  • 移除filters: 使用methods的或者computed來進行替代
  • Vue Router 的變化
  • 構建選項 mode --> 由原來的 mode "history" 更改為 history: createWebHistory()
  • 構建選項 base --> 傳給 createWebHistory() 的第一個引數作為 base
  • 捕獲所有路由 ( /* ) 時,現在必須使用帶有自定義正則表示式的引數進行定義:/:catchAll(.*)
  • push 或者 resolve 一個不存在的命名路由時,將會引發錯誤,而不是導航到根路由 "/" 並且不顯示任何內容
  • router.match (匹配路徑引數的物件) 與 router.resolve(頁面跳轉) 合併在一起為 router.resolve

8. react hook有用麼, 說說對react hook 理解

  • 優點:
  • 讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性
  • 函數語言程式設計元件開發,高度解耦,狀態儲存在執行環境、每個功能都包裹在函式中,整體風格更美觀、優雅;
  • 元件樹層級變淺、元件粒度越細更容易複用程式碼,通過自定義hooks來複用狀態,從而解決了類元件有些時候難以複用邏輯的問題
  • useEffect、useMemo、useCallback讓優化手段更加的簡單(利用hooks鉤子)、useState不用再去考慮 this 的指向問題、useContext讓父子元件傳值更加簡單
  • 缺點:
  • 響應式的useEffect: 需要精確掌握上下文的useEffect的觸發時機。當邏輯較複雜的時候,useEffect容易觸發多次
  • 狀態不同步: 最大的缺點。函式的執行是獨立的,每個函式都有一份獨立的作用域。函式的變數是儲存在執行時的作用域裡面,當我們有非同步操作的時候,經常會碰到非同步回撥的變數引用的是舊狀態
  • 解決及避免:
    • 不要在useEffect裡面寫太多的依賴項,劃分這些依賴項成多個單一功能的useEffect。其實這點是遵循了軟體設計的“單一職責模式”;
    • 如果你碰到狀態不同步的問題,可以考慮下手動傳遞引數到函式;
    • 複雜業務的時候,使用Component代替hooks

9. 工作中優化方向有哪些,依據什麼來確定是否需要優化

內容方向有點多;詳見部落格文章 https://www.cnblogs.com/ljx20180807/p/13543487.html

10. 工作中有沒有遇到比較難的需求,怎麼處理的,效能怎麼樣,你覺得有沒有可以優化的地方

根據實際情況自由發揮

11.帶團隊過程中,團隊和自己所花費時間比例,主要體現在哪些方面**

根據實際情況自由發揮