1. JS 有哪些數據類型,它們的區別有哪些?
JS 數據類型分為基本數據類型和引用數據類型。
- 基本數據類型:String、Number、Boolean、Null、Undefined、Symbol、BigInt,共 7 種,存儲在棧內存,值不可變,按值傳遞。
- 引用數據類型:Object(包含 Array、Function、Date 等),存儲在堆內存,棧內存保存堆內存地址,值可變,按引用傳遞。
2. 數據類型檢測的方式有哪些?
- typeof:檢測基本數據類型(null 會被識別為 object),引用類型除 function 外都識別為 object。
- instanceof:檢測構造函數的 prototype 是否出現在實例的原型鏈上,適用於引用類型。
- prototype.toString.call():最準確的檢測方式,返回 [object 類型] 格式字符串,可識別所有數據類型。
- constructor:通過實例的 constructor 屬性指向其構造函數來判斷。
3. 介紹下 Ajax
Ajax 全稱 Asynchronous JavaScript and XML(異步 JavaScript 和 XML),是一種在不重新加載整個頁面的情況下,與服務器交換數據並更新部分頁面的技術。核心是 XMLHttpRequest 對象(或現代的 fetch API),實現異步請求,提升用户體驗。流程:創建請求對象 → 配置請求參數 → 發送請求 → 監聽狀態變化 → 處理響應數據。
4. 如何判斷一個數據是 NaN?
- isNaN():ES6 新增方法,僅當參數是 NaN 且類型為 Number 時返回 true,避免了全局 isNaN() 的類型轉換問題。
- value !== value:利用 NaN 是唯一不等於自身的值的特性,這是判斷 NaN 的可靠方法。
5. null 和 undefined 的區別
- undefined:表示變量已聲明但未賦值,或對象屬性不存在,是 JS 自動賦予的初始值;typeof undefined 返回 undefined。
- null:表示變量主動賦值為“空值”,代表一個空對象指針;typeof null 返回 object。
- 轉換為數值時:Number(undefined) 是 NaN,Number(null) 是 0。
6. 介紹下閉包,在什麼場景下使用過?
- 定義:閉包是指有權訪問另一個函數作用域中變量的函數,本質是函數作用域鏈的保留。
- 特性:延長外部函數變量的生命週期,隔離作用域避免變量污染。
- 使用場景:① 封裝私有變量(如計數器函數,避免全局變量);② 防抖節流函數的實現;③ 模塊化開發中暴露特定方法。
7. 事件委託是什麼?如何確定事件源?
- 事件委託:利用事件冒泡機制,將子元素的事件綁定到父元素上,由父元素統一處理。優點是減少事件綁定次數、支持動態添加的子元素。
- 確定事件源:在事件處理函數中,通過 target(觸發事件的真實元素)獲取事件源,兼容低版本 IE 用 event.srcElement。
8. 本地存儲與 cookie 的區別
| 特性 | 本地存儲(localStorage/sessionStorage) | Cookie |
|---|---|---|
| 存儲大小 | 約 5MB | 約 4KB |
| 生命週期 | localStorage 永久存儲,sessionStorage 會話結束失效 | 可設置過期時間,默認會話結束失效 |
| 與服務器交互 | 不隨請求發送到服務器 | 每次請求自動攜帶到服務器 |
| 作用域 | 同源頁面共享 | 同源且符合路徑、域名規則 |
9. 簡述下 ES6 的新特性
- 塊級作用域:let、const 關鍵字。
- 箭頭函數:簡化函數寫法,無自己的 this。
- 解構賦值:快速提取數組、對象的屬性。
- 模板字符串:反引號 \` 包裹,支持換行和變量插值 ${}。
- 類與繼承:class、extends 關鍵字,簡化原型鏈寫法。
- 模塊化:import/export 語法。
- 新增數據結構:Set、Map。
- 異步方案:Promise 對象。
- 其他:默認參數、剩餘參數 ...、擴展運算符 ... 等。
10. Let、var 和 const 的區別
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函數作用域/全局作用域 | 塊級作用域 | 塊級作用域 |
| 變量提升 | 存在,可先使用後聲明 | 存在暫時性死區,不可先使用 | 同 let |
| 重複聲明 | 允許 | 不允許 | 不允許 |
| 賦值 | 可多次賦值 | 可多次賦值 | 聲明時必須賦值,且不可修改引用(基本類型不可改,引用類型屬性可改) |
11. 數組都有哪些方法
- 增刪改查:push()(尾增)、pop()(尾刪)、unshift()(頭增)、shift()(頭刪)、splice()(增刪改)、slice()(截取)。
- 遍歷迭代:forEach()、map()、filter()、reduce()、some()、every()。
- 排序與轉換:sort()(排序)、reverse()(反轉)、join()(轉字符串)、concat()(合併數組)。
- 其他:indexOf()/lastIndexOf()(查找索引)、includes()(判斷是否包含)、find()/findIndex()(查找元素/索引)、flat()(扁平化數組)。
12. JSON 如何新增和刪除鍵值對
JSON 本質是符合格式的 JS 對象,操作方式與對象一致:
- 新增鍵值對:key = value 或 obj['key'] = value。
- 刪除鍵值對:使用 delete obj.key 或 delete obj['key']。
13. 簡述下面向對象
面向對象(OOP)是一種編程思想,核心是封裝、繼承、多態。
- 封裝:將數據和操作數據的方法封裝在對象中,隱藏內部細節,暴露公共接口。
- 繼承:子類繼承父類的屬性和方法,實現代碼複用。
- 多態:同一方法在不同對象上有不同的表現形式(JS 中通過重寫方法實現)。
JS 是基於原型的面嚮對象語言,沒有類的概念(ES6 class 是語法糖)。
14. 普通函數與構造函數的區別
- 命名規範:構造函數首字母通常大寫,普通函數首字母小寫。
- 調用方式:構造函數用 new 關鍵字調用,普通函數直接調用。
- 返回值:構造函數默認返回實例對象(手動返回對象會覆蓋);普通函數無 return 時返回 undefined。
- this 指向:構造函數中 this 指向新創建的實例;普通函數中 this 指向調用者(全局調用指向 window/global)。
15. 請簡述原型,原型鏈和繼承
- 原型(prototype):每個函數都有 prototype 屬性,指向原型對象,原型對象包含所有實例共享的屬性和方法。
- 原型鏈:每個實例對象都有 proto 屬性,指向其構造函數的 prototype;當訪問實例屬性時,會依次向上查找原型對象,直到 prototype,這條鏈式結構就是原型鏈。
- 繼承:JS 中繼承基於原型鏈實現,子類實例的 proto 指向父類的 prototype,從而繼承父類的屬性和方法;常見方式有原型鏈繼承、構造函數繼承、組合繼承等。
16. 簡述下對 Promise 的理解以及你在什麼情況下使用過
- Promise 理解:Promise 是解決 JS 異步回調地獄的方案,代表一個異步操作的最終完成(或失敗)及其結果值。有三種狀態:pending(進行中)、fulfilled(已成功)、rejected(已失敗),狀態一旦改變不可逆轉。提供 then()、catch()、finally() 方法鏈式調用。
- 使用場景:① 異步請求(如 axios 基於 Promise 封裝,處理接口請求的成功和失敗);② 讀取文件(js 中 fs.promises 模塊);③ 多個異步操作的串行/並行處理(Promise.all()/Promise.race())。
17. 簡述下 async 的用法
async 用於聲明異步函數,返回值是一個 Promise 對象;await 關鍵字只能在 async 函數中使用,用於等待 Promise 執行完成,暫停函數執行直到 Promise 狀態變為 fulfilled 或 rejected。
- 成功時:await 返回 Promise 的成功值;
- 失敗時:需用 try/catch 捕獲異常,否則會拋出錯誤。
- 作用:將異步代碼以同步的寫法呈現,比 Promise 鏈式調用更簡潔。
18. 簡述下 jQuery
jQuery 是一款輕量級的 JS 庫,核心思想是 Write Less, Do More(寫得更少,做得更多)。它封裝了原生 JS 的 DOM 操作、事件處理、Ajax 請求等功能,解決了瀏覽器兼容性問題。特點:① 簡潔的選擇器;② 鏈式調用;③ 豐富的插件生態;④ 動畫效果便捷。但隨着 Vue、React 等框架的興起,jQuery 在現代前端開發中使用逐漸減少。
19. 什麼是 Sass、Less,為什麼使用它們
- Sass/Less:都是 CSS 預處理器,擴展了 CSS 的語法,增加了變量、混合、嵌套、繼承等特性,讓 CSS 更易維護和複用。Sass 後綴是 .scss(或 .sass),Less 後綴是 .less。
- 使用原因:① 變量:統一管理顏色、字體等樣式屬性;② 嵌套:模擬 DOM 層級結構,增強代碼可讀性;③ 混合:複用公共樣式片段;④ 繼承:減少代碼冗餘;⑤ 模塊化:拆分樣式文件,便於維護。
20. JS 中 call()和 apply()方法的區別
call() 和 apply() 都用於改變函數執行時 this 的指向,第一個參數都是 this 要指向的對象。
-
區別:傳入參數的方式不同。
- call():第一個參數是 this 指向,後續參數是單個參數列表,用逗號分隔。
例:fn.call(obj, arg1, arg2)
- apply():第一個參數是 this 指向,第二個參數是參數數組(或類數組對象)。
例:fn.apply(obj, [arg1, arg2])
21. 為什麼會造成跨域?
跨域是指瀏覽器的同源策略限制,當一個請求的協議、域名、端口三者中任意一個與當前頁面不同,就會產生跨域。同源策略是瀏覽器的安全機制,防止不同源的頁面之間隨意訪問數據,避免 XSS、CSRF 等攻擊。
22. this 有幾種指向?
- 全局環境:this 指向全局對象(瀏覽器中是 window,js 中是 global)。
- 函數直接調用:非嚴格模式下 this 指向全局對象,嚴格模式下 this 是 undefined。
- 對象方法調用:this 指向調用該方法的對象。
- 構造函數調用:this 指向新創建的實例對象。
- call()**/apply()/**bind() 調用:this 指向傳入的第一個參數。
- 箭頭函數:沒有自己的 this,this 指向箭頭函數定義時所在作用域的 this。
- 事件處理函數:this 指向觸發事件的 DOM 元素。
23. 請説出三種減少頁面加載時間的方式
- 資源壓縮:壓縮 JS、CSS、HTML 文件,減小文件體積;壓縮圖片(WebP 格式、圖片壓縮工具)。
- 資源緩存:設置合理的 HTTP 緩存頭(如 Cache-Control、Expires),利用 localStorage 緩存不常變化的靜態資源。
- 減少 HTTP 請求:合併 CSS/JS 文件,使用雪碧圖合併小圖標,採用懶加載加載非首屏資源。
- CDN 加速:將靜態資源部署到 CDN 服務器,就近獲取資源,提高加載速度。
24. 什麼是 JSONP,工作原理是什麼?它為什麼不是真正的 Ajax?
- JSONP:是一種跨域請求解決方案,全稱 JSON with Padding。
- 工作原理:利用 <script> 標籤不受同源策略限制的特性,動態創建 <script> 標籤,請求後端接口,後端返回一個函數調用的字符串,函數參數是需要的 JSON 數據,前端提前定義好該函數,從而獲取數據。
- 不是真正的 Ajax:Ajax 基於 XMLHttpRequest 對象實現,而 JSONP 基於 <script> 標籤的請求,不依賴 XMLHttpRequest,且只支持 GET 請求,不支持 POST 等其他請求方法。
25. 説幾種數組去重方式
- 利用 Set:[...new Set(arr)],簡潔高效,ES6 推薦方法。
- 利用 indexOf/includes:遍歷數組,判斷元素是否已存在於新數組中,不存在則添加。
- 利用 filter + indexOf:filter((item, index) => arr.indexOf(item) === index)。
- 利用對象屬性唯一性:將數組元素作為對象的鍵,避免重複。
26. 簡述下深淺拷貝,並説下如何分別實現,以及使用場景
-
淺拷貝:只複製對象的第一層屬性,若屬性是引用類型,複製的是地址,修改新對象會影響原對象。
- 實現方法:assign()、擴展運算符 {...obj}、數組 slice()/concat()。
- 使用場景:複製只有基本類型屬性的簡單對象。
-
深拷貝:複製對象的所有層級屬性,新對象與原對象完全獨立,修改互不影響。
- 實現方法:parse(JSON.stringify(obj))(缺點:無法複製函數、RegExp 等)、遞歸手寫深拷貝、lodash.cloneDeep()。
- 使用場景:複製包含引用類型屬性的複雜對象(如嵌套對象、數組)。
27. 為什麼 JS 是弱類型語言
弱類型語言的特點是變量類型不固定,支持隱式類型轉換。JS 中變量聲明時不需要指定類型,賦值後類型可以隨時改變;在運算時,JS 會自動將不同類型的值轉換為相同類型再計算(如 1 + '2' = '12')。與之相對的是強類型語言(如 Java),變量類型固定,必須顯式轉換類型。
28. 怎麼轉換 Less 為 CSS
- 使用 Less 官方編譯器:安裝 js 後,通過 npm 安裝 less 包,執行命令 lessc styles.less styles.css 編譯。
- 構建工具集成:在 Webpack/Vite 等構建工具中配置 less-loader,打包時自動將 Less 轉換為 CSS。
- 編輯器插件:使用 VS Code 的 Easy LESS 插件,保存 Less 文件時自動生成對應的 CSS 文件。
29. ECharts 使用最多的是什麼?
ECharts 是百度開源的可視化圖表庫,使用最多的是各類統計圖表的繪製,包括:
- 折線圖/柱狀圖:用於展示數據的趨勢和對比。
- 餅圖/環形圖:用於展示數據的佔比情況。
- 地圖:用於展示地理相關的數據分佈。
- 儀表盤:用於展示關鍵指標的數值。
核心是通過配置項 option 設置圖表的數據源、樣式、交互等屬性。
30. for 循環和 map 循環有什麼區別?
- 返回值:for 循環無返回值,需手動操作數組;map 循環返回一個新數組,新數組元素是原數組元素經過回調函數處理後的結果。
- 功能:for 循環可用於遍歷、修改原數組、跳出循環(break/continue);map 循環主要用於映射轉換數組,不能中斷循環。
- 可讀性:map 循環寫法更簡潔,語義化更強,適合數組的批量轉換;for 循環更靈活,適合複雜的遍歷邏輯。
31. 請寫一個簡單的類與繼承
// 父類
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`我是${this.name},今年${this.age}歲`);
}
}
// 子類繼承父類
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // 調用父類構造函數
this.grade = grade;
}
study() {
console.log(`${this.name}在${this.grade}年級學習`);
}
}
// 實例化
const stu = new Student('小明', 12, 6);
stu.sayHello(); // 我是小明,今年12歲
stu.study(); // 小明在6年級學習
32. 同步與異步的區別?阻塞與非阻塞的區別?
同步與異步
- 同步:代碼按順序執行,前一個任務完成後才執行下一個任務,主線程會被阻塞。例:普通函數調用、alert()。
- 異步:任務不會阻塞主線程,發起後繼續執行後續代碼,任務完成後通過回調/事件通知結果。例:setTimeout、Ajax 請求。
阻塞與非阻塞
- 阻塞:線程執行任務時,必須等待任務完成才能繼續執行其他操作,線程處於等待狀態。
- 非阻塞:線程執行任務時,若任務未完成,可立即返回去執行其他操作,無需等待,通過輪詢或回調獲取任務結果。
- 關係:同步 ≠ 阻塞,異步 ≠ 非阻塞,它們是不同維度的概念(同步異步描述任務的執行順序,阻塞非阻塞描述線程的狀態)。
33. HTTP 是什麼?有什麼特點?
HTTP 全稱 HyperText Transfer Protocol(超文本傳輸協議),是用於在客户端和服務器之間傳輸數據的應用層協議,基於 TCP/IP 協議。
-
特點:
- 無狀態:協議本身不記錄客户端的請求狀態,每次請求都是獨立的(可通過 Cookie/Session 保持狀態)。
- 無連接:HTTP 1.0 中,每次請求都要建立新的 TCP 連接,請求完成後斷開;HTTP 1.1 支持持久連接(Keep-Alive)。
- 簡單快速:請求格式簡單,客户端向服務器發送請求方法和路徑,服務器返回狀態碼和數據。
- 靈活:支持多種數據類型(如文本、圖片、視頻等)。
34. HTTP 協議和 HTTPS 的區別
| 特性 | HTTP | HTTPS |
|---|---|---|
| 安全性 | 明文傳輸,數據易被竊取、篡改 | 加密傳輸(SSL/TLS 協議),數據安全 |
| 端口 | 默認 80 | 默認 443 |
| 證書 | 無需證書 | 需要 CA 頒發的 SSL 證書 |
| 性能 | 速度快,無加密解密開銷 | 速度稍慢,有加密解密過程 |
| 資源消耗 | 低 | 高 |
35. 原型和繼承,prototype,call 和 apply 繼承的區別
- 原型繼承:將子類的 prototype 指向父類的實例,子類實例可繼承父類原型上的屬性和方法。缺點:父類的引用類型屬性會被所有子類實例共享;無法向父類構造函數傳參。
- call/apply 繼承:在子類構造函數中調用父類構造函數,通過 call()/apply() 改變父類 this 指向子類實例,實現父類實例屬性的繼承。缺點:無法繼承父類原型上的方法。
- 組合繼承:結合原型繼承和 call/apply 繼承,既繼承父類實例屬性,又繼承父類原型方法,是最常用的繼承方式。
36. 説幾種數組和字符串的方法及他們的作用
數組方法
- map():遍歷數組,返回新數組,元素為回調函數處理結果。
- filter():過濾數組元素,返回符合條件的新數組。
- reduce():累計計算數組元素,返回最終結果(如求和、求積)。
- find():返回數組中第一個符合條件的元素。
字符串方法
- split():將字符串按分隔符分割為數組。
- indexOf()/includes():查找子字符串是否存在,返回索引或布爾值。
- substring()/slice():截取字符串的指定部分。
- replace():替換字符串中的指定內容。
37. 箭頭函數與普通函數的區別
- this 指向:箭頭函數無自己的 this,指向定義時所在作用域的 this;普通函數 this 指向調用者。
- 構造函數:箭頭函數不能作為構造函數,不能用 new 調用;普通函數可以。
- 參數:箭頭函數沒有 arguments 對象,可使用剩餘參數 ...args;普通函數有 arguments。
- 原型:箭頭函數沒有 prototype 屬性;普通函數有。
- 寫法:箭頭函數寫法更簡潔,適合回調函數;普通函數寫法更靈活。
38. 什麼是 JS 內存泄露
內存泄露是指程序中已不再使用的內存沒有被及時釋放,導致內存佔用越來越高,最終影響程序性能甚至崩潰。JS 中常見的內存泄露場景:
- 意外的全局變量(如未聲明的變量)。
- 閉包導致的變量未釋放。
- 未清除的定時器/事件監聽器。
- DOM 元素被刪除但仍有引用(如變量保存了已刪除的 DOM 節點)。
39. 如何對網站的文件和資源進行優化
- 靜態資源優化:壓縮 JS/CSS/HTML,圖片格式轉換(WebP)、圖片懶加載、雪碧圖合併小圖標。
- 資源加載優化:使用 CDN 加速,預加載關鍵資源(preload),預解析 DNS(dns-prefetch)。
- 代碼優化:減少 HTTP 請求,合併文件;刪除無用代碼(Tree Shaking);延遲加載非首屏腳本。
- 緩存優化:設置強緩存和協商緩存,利用 localStorage 緩存靜態數據。
- 服務器優化:啓用 Gzip/Brotli 壓縮,使用 HTTP/2 協議(多路複用)。
40. 簡述 Ajax 的執行過程以及常見的 HTTP 狀態碼
Ajax 執行過程
- 創建 XMLHttpRequest 對象:const xhr = new XMLHttpRequest()。
- 配置請求參數:open(method, url, async)(method:請求方法;url:請求地址;async:是否異步)。
- 設置響應處理函數:onreadystatechange = function() {},監聽 readyState 變化。
- 發送請求:send(data)(POST 請求需傳遞數據)。
- 處理響應:當 readyState === 4 且 status === 200 時,獲取響應數據 responseText。
常見 HTTP 狀態碼
- 2xx 成功:200(請求成功)、201(創建資源成功)。
- 3xx 重定向:301(永久重定向)、302(臨時重定向)、304(資源未修改,使用緩存)。
- 4xx 客户端錯誤:400(請求參數錯誤)、401(未授權)、403(禁止訪問)、404(資源不存在)。
- 5xx 服務器錯誤:500(服務器內部錯誤)、503(服務器不可用)。
41. 預加載和懶加載的區別,預加載在什麼時間合適
區別
- 預加載:提前加載未來可能需要的資源(如圖片、JS 文件),加載完成後緩存,當用户需要時直接從緩存讀取,提升體驗。主動加載,會增加首屏加載時間。
- 懶加載:延遲加載非首屏資源,只有當資源進入可視區域時才加載,減少首屏加載時間,提升頁面加載速度。被動加載,適用於圖片、視頻等大量靜態資源。
預加載合適的時間
預加載應在首屏資源加載完成後進行,避免搶佔首屏資源的帶寬,影響首屏渲染速度。可通過 window.onload 事件觸發,或在頁面空閒時(requestIdleCallback)執行。
42. jQuery 選擇器有哪些?
jQuery 選擇器基於 CSS 選擇器,分為以下幾類:
- 基本選擇器:ID 選擇器($('#id'))、類選擇器($('.class'))、標籤選擇器($('div'))、通配符選擇器($('*'))。
- 層級選擇器:後代選擇器($('parent child'))、子元素選擇器($('parent > child'))、相鄰兄弟選擇器($('prev + next'))。
- 過濾選擇器:基本過濾(:first、:last、:eq(index))、內容過濾(:contains(text))、可見性過濾(:visible、:hidden)。
- 屬性選擇器:$('[attr]')、$('[attr=value]')。
43. jQuery 插入節點的方法
-
內部插入:
- append():在元素內部末尾插入節點。
- prepend():在元素內部開頭插入節點。
-
外部插入:
- after():在元素外部後面插入節點。
- before():在元素外部前面插入節點。
- 替換節點:replaceWith():用新節點替換原節點。
- 包裹節點:wrap():用指定節點包裹每個匹配元素。
44. Get 和 Post 區別
| 特性 | GET | POST |
|---|---|---|
| 請求參數 | 拼接在 URL 後,可見 | 放在請求體中,不可見 |
| 數據長度 | 受 URL 長度限制,較小 | 無限制,可傳輸大量數據 |
| 安全性 | 低,參數暴露在 URL | 高,參數隱藏在請求體 |
| 緩存 | 可被瀏覽器緩存 | 不可被緩存 |
| 冪等性 | 冪等(多次請求結果相同) | 非冪等(多次請求可能產生不同結果) |
| 用途 | 讀取數據 | 提交/修改數據 |
45. 什麼是 CSRF 攻擊
CSRF 全稱 Cross-Site Request Forgery(跨站請求偽造),是一種網絡攻擊手段。攻擊者誘導用户在已登錄目標網站的情況下,訪問惡意網站,利用用户的登錄狀態向目標網站發送偽造的請求,從而執行非用户意願的操作(如轉賬、修改密碼)。防禦措施:① 驗證 Referer 字段;② 使用 CSRF Token;③ 驗證碼驗證。
46. 如何遍歷一個多維數組?
- 遞歸遍歷:遍歷數組元素,若元素是數組則遞歸調用遍歷函數,否則處理元素。
function traverse(arr) {
arr.forEach(item => {
if (Array.isArray(item)) {
traverse(item);
} else {
console.log(item);
}
});
}
- 扁平化後遍歷:用 flat() 方法將多維數組扁平化為一維數組,再遍歷。
const arr = [1, [2, [3, 4]]];
arr.flat(Infinity).forEach(item => console.log(item));
47. Axios 的特性?
Axios 是基於 Promise 的 HTTP 客户端,支持瀏覽器和 Node.js,核心特性:
- 支持 Promise API,可鏈式調用。
- 攔截請求和響應(請求攔截器處理 token,響應攔截器統一處理錯誤)。
- 轉換請求和響應數據(如自動轉換 JSON 數據)。
- 取消請求。
- 防止 CSRF 攻擊。
- 客户端支持防禦 XSRF。
- 支持多種請求方法(GET、POST、PUT、DELETE 等)。
48. 在地址欄輸入一個 URL,到頁面呈現出來,中間發生了什麼?
- DNS 解析:將域名轉換為對應的 IP 地址。
- 建立 TCP 連接:客户端與服務器通過三次握手建立連接(HTTP/1.1 默認為持久連接)。
- 發送 HTTP 請求:客户端向服務器發送請求行、請求頭、請求體。
- 服務器處理請求:服務器解析請求,處理業務邏輯,生成響應數據。
- 服務器返回響應:服務器向客户端發送響應行、響應頭、響應體(HTML 等資源)。
- 關閉 TCP 連接:通過四次揮手關閉連接(若開啓 Keep-Alive 則保持連接)。
-
瀏覽器解析渲染頁面:
- 解析 HTML 生成 DOM 樹;
- 解析 CSS 生成 CSSOM 樹;
- 結合 DOM 樹和 CSSOM 樹生成渲染樹;
- 佈局(Layout):計算元素的位置和大小;
- 繪製(Paint):將渲染樹繪製到屏幕上。
49. 異步操作的解決方案
- 回調函數:最基礎的方案,將異步操作的結果處理邏輯傳入回調函數,但容易導致回調地獄。
- Promise:解決回調地獄,通過 then()/catch() 鏈式調用,支持多個異步操作的串行/並行處理。
- async/await:基於 Promise 的語法糖,以同步寫法實現異步操作,代碼更簡潔易讀。
- Generator 函數:通過 yield 暫停函數執行,next() 恢復執行,可實現異步流程控制(較少使用)。
50. map 和 forEach 的區別
| 特性 | map | forEach |
|---|---|---|
| 返回值 | 返回新數組,元素為回調處理結果 | 無返回值(返回 undefined) |
| 功能 | 映射轉換數組,適合生成新數組 | 遍歷數組,適合執行操作(如打印、修改原數組) |
| 中斷循環 | 無法中斷,必須遍歷所有元素 | 無法中斷(無 break/continue) |
| 性能 | 稍慢(需創建新數組) | 稍快(無新數組創建) |
51. TCP 和 UDP 的區別
| 特性 | TCP | UDP |
|---|---|---|
| 連接性 | 面向連接(三次握手建立連接) | 無連接(直接發送數據) |
| 可靠性 | 可靠傳輸,保證數據有序、不丟失 | 不可靠傳輸,不保證數據到達 |
| 傳輸方式 | 流式傳輸,數據無邊界 | 數據包傳輸,數據有邊界 |
| 擁塞控制 | 有擁塞控制和流量控制 | 無擁塞控制 |
| 速度 | 較慢 | 較快 |
| 用途 | 文件傳輸、網頁加載、郵件發送 | 視頻直播、語音通話、實時遊戲 |
52. BOM 和 DOM 的區別
- DOM:全稱 Document Object Model(文檔對象模型),是 HTML/XML 文檔的編程接口,將文檔解析為樹形結構,提供操作元素、屬性、事件的方法(如 getElementById())。核心是 document 對象。
- BOM:全稱 Browser Object Model(瀏覽器對象模型),是與瀏覽器窗口交互的接口,提供操作瀏覽器窗口、地址欄、歷史記錄等的方法(如 open()、location.href)。核心是 window 對象,DOM 是 BOM 的一部分。
53. 簡述下 Git 操作
Git 是分佈式版本控制系統,常用操作:
- 初始化倉庫:git init。
- 克隆倉庫:git clone <url>。
- 文件操作:git add <file>(添加到暫存區)、git commit -m "message"(提交到本地倉庫)。
- 分支操作:git branch(查看分支)、git branch <name>(創建分支)、git checkout <name>(切換分支)、git merge <name>(合併分支)。
- 遠程操作:git remote add origin <url>(關聯遠程倉庫)、git push -u origin master(推送代碼)、git pull(拉取代碼)。
- 版本回退:git log(查看提交記錄)、git reset --hard <commit-id>(回退到指定版本)。
54. 什麼是 Node.js?
Node.js 是基於 Chrome V8 引擎的 JavaScript 運行時環境,讓 JS 可以脱離瀏覽器運行在服務器端。特點:
- 非阻塞 I/O:處理高併發請求性能優異。
- 事件驅動:基於事件循環機制,異步處理請求。
- 豐富的模塊生態:通過 npm 管理大量第三方模塊。
- 跨平台:支持 Windows、Linux、macOS 等系統。
用途:搭建後端服務器、開發 CLI 工具、構建前端工程化工具(如 Webpack)。
55. 遍歷數組,遍歷對象,遍歷字符串的方法都有哪些?哪些可以打斷?
遍歷數組
- 可打斷的方法:for 循環(break/continue)、..of 循環(break/continue)。
- 不可打斷的方法:forEach()、map()、filter()、reduce()。
遍歷對象
- ..in:遍歷對象的可枚舉屬性(包括原型鏈上的屬性),可通過 break 打斷。
- keys()/Object.values()/Object.entries():返回數組後遍歷,可結合 for 循環打斷。
遍歷字符串
- 可打斷的方法:for 循環、..of 循環。
- 不可打斷的方法:split('').forEach()。
56. 迴流和重繪
- 迴流(Reflow):當元素的佈局屬性發生變化(如寬高、位置、DOM 結構),瀏覽器需要重新計算元素的幾何屬性和位置,重新構建渲染樹,這個過程叫回流。迴流代價較高,會觸發重繪。
- 重繪(Repaint):當元素的樣式屬性發生變化(如顏色、背景色),但不影響佈局時,瀏覽器只需重新繪製元素外觀,這個過程叫重繪。重繪代價低於迴流。
- 觸發迴流的操作:添加/刪除 DOM 元素、改變元素尺寸、改變窗口大小、offsetWidth/offsetHeight 等屬性的讀取。
- 優化:減少迴流次數(如批量修改樣式、使用 documentFragment 批量添加 DOM)。
57. 節流和防抖
- 防抖(Debounce):觸發事件後,在指定時間內沒有再次觸發事件,才執行回調函數;若在指定時間內再次觸發,則重新計時。適用於搜索框輸入聯想、窗口大小調整等場景。
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
- 節流(Throttle):觸發事件後,每隔指定時間執行一次回調函數,在指定時間內多次觸發只執行一次。適用於滾動加載、鼠標移動、按鈕點擊等場景。
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
58. 宏任務和微任務
宏任務和微任務是 JS 異步任務的分類,事件循環中執行順序為:先執行同步代碼 → 執行所有微任務 → 執行一個宏任務 → 再執行所有微任務,以此循環。
- 宏任務(Macrotask):執行時間較長的任務,包括 setTimeout、setInterval、I/O、UI 渲染、script 整體代碼。
- 微任務(Microtask):執行時間較短的任務,包括 then()/catch()/finally()、async/await、queueMicrotask()、MutationObserver。
59. 什麼是裝飾器?
裝飾器(Decorator)是一種設計模式,用於在不修改原函數/類代碼的前提下,動態地為其添加額外功能。ES7 中提出了裝飾器語法(目前是提案,需通過 Babel 編譯)。
- 類裝飾器:用於裝飾類,修改類的行為。
- 方法裝飾器:用於裝飾類的方法,修改方法的執行邏輯。
- 用途:日誌記錄、性能監控、權限校驗等。例如:用裝飾器記錄函數的執行時間。
60. 什麼是迭代器?
迭代器(Iterator)是一種接口,為不同的數據結構提供統一的遍歷機制。任何數據結構只要部署了 Iterator 接口,就可以通過 for...of 循環遍歷。
- 迭代器的特性:有一個 next() 方法,每次調用返回一個對象 { value: 當前值, done: 是否遍歷完成 }。
- 原生支持迭代器的數據結構:數組、字符串、Set、Map。
- 自定義迭代器:通過 iterator 屬性為對象部署迭代器接口。
61. 什麼是前端微服務?
前端微服務是借鑑後端微服務的思想,將大型前端應用拆分為多個獨立的、可獨立開發、測試、部署的小型應用,每個小型應用稱為一個“微應用”。
-
核心特點:
- 獨立部署:每個微應用可單獨發佈,不影響其他微應用。
- 技術棧無關:不同微應用可使用不同的前端框架(如 Vue、React)。
- 共享基礎資源:共享公共組件、工具庫、狀態管理等。
- 運行時集成:通過主應用(基座)加載微應用,實現頁面跳轉和通信。
- 實現方案:基於 qiankun、single-spa 等框架。