1.data為什么是一個函數而不是對象
維度 | 對象形式 | 函數形式 |
---|---|---|
數據隔離性 | 所有實例共享同一對象,導致數據污染 | 每個實例擁有獨立數據副本 |
復用安全性 | 不適用于可復用組件 | 支持組件安全復用 |
語言機制 | 引用傳遞引發副作用 | 函數返回值實現作用域隔離(閉包) |
框架約束 | 僅根實例允許使用 | 組件必須使用 |
data 函數在每次調用時形成閉包,返回的對象屬于當前組件實例的作用域鏈,不會被其他實例訪問或修改
2. Proxy 比 defineProperty到底好在哪
Proxy 的優勢本質在于其設計理念的先進性:以對象為顆粒度的代碼模式取代了 defineProperty 以屬性為顆粒度的攔截模式,這使得 Proxy 在功能覆蓋、性能優化和開發體驗式均實現了顯著提升。這也是以 Vue3 選擇 Proxy 重構響應式系統的核心原因。
Proxy 是 ES6+,不支持 IE11 等舊瀏覽器,而 defineProperty(ES 5)兼容性更廣。
3. $nextTick 的原理及作用?
$nextTick 等待下一次 DOM 更新刷新的工具方法。
Vue 的 nextTick 其本質是對 JavaScript 執行原理的 EventLoop 的應用。Vue 的 DOM 更新是異步的,當數據變化時,Vue 會將 DOM 更新的操作緩存在一個隊列中,等待同一事件循環內的所有數據變化完成后,在同一進行試圖更新。這種機制通過合并多次數據變更 減少不必要的 DOM 操作,優化性能。
源碼實現機制:
- 回調隊列(callbacks): $nextTick 將用戶傳入的回調函數推入隊列,保證多個 $nextTick 調用合并為一個異步任務;
- 執行異步函數(timerFunc):根據瀏覽器支持的情況選擇最優異步方案:
- 微任務優先:Promise>MutationObserver>setImmediate>setTimeout
- 兼容性處理:舊版瀏覽器降級為宏任務
- 防止重復執行(pending):通過標志位確保同一時間只執行一次隊列刷新
作用:
- 獲取更新后的 DOM(在特定的生命周期【created、mounted】中確保 DOM 就緒)
- 優化高頻操作
4.對 keep-alive 的核心理解與實現原理分析?
keep-alive 是 vue 中的內置組件,能在組件切換過程中將狀態仍保留在內存中,防止重復渲染 DOM
props 屬性:
- include - 字符串或正則表達式,只有名稱匹配的組件會被緩存
- exclude - 字符串或者正則表達式,任何名字匹配的組件都不會被緩存
- max - 數字,最多可以緩存多少組件實例
核心理解: keep-alive 是 Vue.js 的內置組件,其核心作用是 通過緩存不活躍的組件實例,避免重復銷毀和重建,從而提高性能并保留組件狀態(如表單輸入、滾動位置等)。其本質是通過內存管理實現組件的 “失活” 與 “激活”。
實現原理:
- 存儲結構:keep-alive 內部維護一個緩存對象(cache)和一個 緩存鍵數組(keys),用于存儲組件實例的虛擬節點(vnode)及其唯一標識 key。
- 復用邏輯:當組件切換時,若匹配[ include, exclude,max]到緩存中的 key,則直接復用緩存的 vnode 及其管理實例(componentInstance)和 DOM 元素($el)
5.Vue 單頁應用與多頁應用的區別?
SPA 是一種 網絡應用程序或者網站的模型
優點:
- 具有桌面應用的即時性、網站的可移植性和可訪問性
- 用戶體驗好、快,內容的改變不需要更新加載整個頁面
- 良好的前后端分離,分工更明確
缺點: - 不利于搜索引擎的抓取
- 首次渲染速度相對較慢
對比維度 | 單頁應用(SPA) | 多頁應用(MPA) |
---|---|---|
頁面加載方式 | 首次加載全部資源,后續局部動態更新(無刷新) | 每次跳轉加載完整新頁面(整頁刷新) |
用戶體驗 | 切換流暢,接近原生應用 | 切換有延遲,傳統網頁體驗 |
開發復雜度 | 較高(需前端路由、狀態管理、組件化) | 較低(傳統多頁面開發,邏輯分散) |
技術棧 | Vue/React + 前端路由(Vue Router) + 狀態管理(Vuex/Pinia) | 多頁面獨立 HTML,可能搭配后端模板(如 JSP/PHP) |
資源復用 | 公共資源(JS/CSS)僅加載一次 | 公共資源可能重復加載 |
首屏性能 | 首屏較慢(需加載框架代碼),需代碼分割優化 | 首屏較快(僅加載當前頁資源) |
路由機制 | 前端路由(Hash/History 模式) | 后端路由或傳統 < a > 標簽跳轉 |
SEO 支持 | 需額外優化(如 SSR、預渲染) | 天然支持(靜態內容易被抓取) |
適用場景 | 交互復雜的中后臺系統、Web 應用(如在線工具、社交平臺) | 內容為主的網站(如企業官網、博客) |
維護成本 | 組件化提升復用性,但大型項目狀態管理復雜 | 重復代碼多,多頁面維護成本高 |
數據傳遞 | 全局狀態管理(如 Vuex)或組件通信 | URL 參數、Cookie、LocalStorage |
安全性 | 前端邏輯暴露較多,需防范 XSS/CSRF | 后端處理核心邏輯,安全性較高 |
服務器壓力 | 首屏后請求少(API 交互為主) | 每次跳轉均需服務器返回完整頁面 |
6. Vue 模板到 Render 函數的編譯過程解析?
解析模板生成 AST => 靜態節點優化 => 生成渲染函數
- 模板解析階段: 生成抽象語法樹(AST),將非結構化的模板字符串轉換為可編程操作的樹形結構數據,描述模板的語法結構。
- 詞法分析: 使用正則表單時逐字符解析模板,識別 HTML 標簽、屬性、指令(v-if)、插值表達式({{}})等。
- 語法分析:構建樹形結構 AST,每個節點表示一個元素或表達式
- 關鍵模板:Vue 的 parse 函數
- 優化階段: 標記靜態節點,通過跳過靜態節點的比對減少虛擬 DOM 更新時的計算量,提升渲染效率
- 靜態節點識別: 深度遍歷 AST,標記不會變化的 節點(如純文本、無動態綁定的元素)
- 靜態提升(vue3):將靜態節點提升到渲染函數的外部,避免重復創建
- 關鍵模塊:optimizer 模板、
- 代碼生成階段:生成渲染函數,將優化后的 AST轉化為可執行的 Javascript 代碼(render 函數),生成輕量級的虛擬 DOM 描述,供運行時渲染器高效的更新視圖。
- 遞歸遍歷 AST:根據節點類型生成對應的 Javascript 代碼片段。
- 拼接代碼字符串:使用 _c(創建元素)、_v(創建文本節點)、_s(字符串化數據)等輔助函數構建虛擬 DOM
- 關鍵模塊: generate 函數
7. 描述一下 Vue 自定義指令
Vue 自定義指令是一種針對 DOM 元素底層操作的復用邏輯機制,允許開發者封裝(如焦點控制、樣式操作、事件監聽等行為)。與組件(復用 UI 邏輯)和 組合式函數(復用狀態邏輯)不同,自定義指令專注于直接操作 DOM ,適合解決跨組件的通用交互需求。常見應用包括焦點控制、拖拽交互、懶加載等,是復雜交互場景下的重要工具。
注冊指令:全局注冊 和 局部注冊 (directive)
應用場景:
- 防抖
- 圖片懶加載
- 一鍵 Copy 功能
- 權限校驗
8.生命周期
生命周期 | 描述 |
---|---|
beforeCreate | 組件實例被創建之初,組件的屬性生效之前 |
created | 組件實例已經完全創建,data 數據初始化,屬性也綁定,但真實的 DOM 還沒生成,$el( 虛擬 DOM ) 還不可用 |
beforeMount | 在掛在之前被調用,$el 初始化:相關的 render 函數首次被調用 |
mounted | el 被新創建的 vm.$el 替換,完成掛載 |
beforeUpdate | 組件數據更新之前調用,發生在虛擬 DOM 打補丁之前 |
update | 組件數據更新之后 |
activited | keep-alive 專屬,組件被激活時調用 |
deactivated | keep-alive 專屬,組件被銷毀時調用 |
beforeDestory | 組件銷毀前調用 |
destoryed | 組件銷毀后調用 |
初始化順序: props、methods、data
父子組件的加載的生命周期:父 beforeCreate => 父 create => 父 beforeMount => 子 beforeCreate => 子 create => 子 beforeMount => 子 mounted => 父 mounted
9. 在哪個生命周期內調用異步請求
created、beforeMount 、mounted
推薦 created 中請求異步
- 能更快的獲取到服務端數據,減少頁面的 loading 時間
- ssr 不支持 beforeMount 、mounted 鉤子函數,所以放在 created 中有助于一致性
- 請求在 mounted 中有可能會導致頁面閃動
10. SSR
SSR 服務端渲染,在服務端將標簽渲染成整個 html 片段,直接返回給客戶端
優點:
1). 更好的SEO( 搜索引擎優化 )
2). 首屏加載更快,不需要下載 Vue 編譯后的 js 和 css
缺點:
1). 更多的開發條件限制:例如服務端渲染只支持 beforeCreate 和 created 這兩個鉤子函數
2). 更多的服務器負載: 在服務器中渲染完整的應用程序,顯然會比僅僅提供靜態文件的 server 更加大量占用 CPU 資源
11.說說你對 VUE 的理解?
Vue.js 是一款漸進式 JavaScript 框架,其核心理念是“逐步增強”,允許開發者從簡單頁面到復雜單頁應用(SPA)平滑升級,無需全盤重構。
- 響應式系統:基于 Proxy (Vue3.x)實現數據雙向綁定,自動追蹤依賴并高效更新視圖。例如,通過 ref 和 reactive 管理狀態,結合編譯優化(如靜態提升、補丁標記)、運行時性能提高顯著
- 模板語法:接近原生 HTML 的模板語法,降低學習門檻,適合傳統 Web 開發者快速上手
- 漸進式遷移:支持按需引入功能模塊(如路由、狀態管理),避免一次性技術債務
Vue 的核心特征:
- 數據驅動 (MVVM)
- 組件化:把圖形、非圖形的各種邏輯均抽象為一個統一的概念(組件)來實現開發的模式
- 指令系統
組件化的優勢:
- 降低整個系統的耦合度,在保持接口不變的情況下,我們可以替換不同的組件快速完成需求,例如輸入框,我們可以替換為日歷、時間、范圍等組件作具體的實現
- 調試方便,由于整個系統是通過組件組合起來的,在出現問題的時候,可以排除法直接移除組件、或者根據報錯的組件快速定位問題,是因為每個組件之間低耦合,職責單一,所以邏輯分析會比整個系統要簡單
- 提高可維護性,由于每個組件的職責單一,并且組件在系統是被復用的,所以對代碼進行優化可獲得系統的整體升級
指令系統:
指令是帶有 v- 前綴的特殊屬性作用:當表達式的值改變時,將其產生的連帶影響,響應式的作用于 DOM 。v-if 、v-for、v-bind、v-model
12. Vue 和 React 對比
相同點:
- 都有組件化思想
- 都支持服務器端渲染
- 都有 Virtual DOM (虛擬 DOM)
- 數據驅動視圖
- 都有支持 native 的方案:Vue 的 weex、React 的React native
- 都有自己的構建工具:Vue 的 vue-cli、React 的 create React App
區別
- 數據變化的實現原理不同。React 使用的是不可變數據,而 Vue 使用的是可變數據
- 組件化通信的不同。React 中我們通過使用回調函數進行通信,而 Vue 中子組件向父組件傳遞消息方式有兩種方式:事件和回調函
- diff 算法不同。React 主要使用 diff 隊列保存需要更新哪些 DOM,得到 patch 樹,再統一操作批量更新 DOM。Vue 使用雙指針,邊對比,邊更新 DOM
維度 | Vue 優勢 | React 優勢 |
---|---|---|
開發效率 | 開箱即用,適合快速迭代 | 靈活架構,適合長期維護與擴展 |
性能 | 中小型應用更優,響應式更新精準 | 復雜應用優化潛力大,并發模式提升流暢度 |
學習成本 | 低門檻,文檔友好 | 高上限,適合技術深度探索 |
生態 | 國內支持強,工具鏈完善 | 全球化生態,企業級方案成熟 |
13.說說對雙向綁定的理解
MVVM
VM (ViewModel)的主要職責是:
- 數據變化后更新視圖
- 視圖變化后更新數據
流程:
- new Vue() 首先執行初始化,對 data 執行響應化處理,這個過程發生在 Observe 中
- 同時對模版執行編譯,找到其中動態綁定的數據,從 data 中初始化視圖,這個過程發生在 Complie 中
- 同時定義一個更新函數和 Watcher ,將來對應數據變化時 Watcher 會調用更新函數
- 由于 data 的某個 key 在視圖中可能出現多次,所以每個 key 都需要一個管家 Dep 來管理多個 Watcher
- 將來 data 中的數據一旦發生變化,會首先找到對應的 Dep ,通知所有的 Watcher 執行更新函數
14.Vue的性能優化有哪些?
1. 編碼階段
1.1 減少響應式依賴
- 精簡 data 數據:僅將需要響應式變化的變量放入 data,避免無意義的數據劫持(Object.defineProperty 或 Proxy)帶來的性能損耗
- 凍結靜態數據:對純展示的長列表使用 Object.freeze()凍結,跳過響應式處理
1.2 條件渲染與列表優化
- v-if 與 v-show 選擇
- v-for 優化:
- 始終為列表設置唯一 key,幫助 Vue 高效復用 DOM
- 避免 v-for 與 v-if 同級使用,優先用計算屬性過濾數據
- 大數據列表使用 虛擬滾動(如 vue-vurtual-scroller),僅渲染可視區域元素,內存占用降低 50%
** 1.3計算屬性與事件優化**
- computed 緩存:替代方法(methods)處理復雜邏輯,避免重復計算。
- 事件代理:在 v-for 中綁定事件是,使用事件代理減少事件監聽數量
2.組件與架構優化
2.1組件懶加載
- 路由懶加載
- 組件異步加載
2.2 緩存與復用
- keep-alive 緩存組件
- v-once 靜態內容:標記永不變化的靜態部分,跳過后續 Diff 過程
2.3 輕量化組件
- 函數式組件:無狀態組件標記為函數式(functional:true),減少實例化開銷
- 邏輯復用
3打包階段
3.1代碼壓縮與分割
- Gzip 壓縮:通過 compression-webpack-plugin壓縮代碼
- 代碼分割(code Splitting):利用 SplitChunksPlugin 抽離公共模塊(lodash、vue)
- Tree Shaking:移除未使用代碼(Vue 3 默認支持)
3.2資源優化
- CDN 加速
- 圖片懶加載
- (圖片)webP 格式
4.用戶體驗
- 骨架圖: 首屏加載期間展示占位圖,降低用戶等待焦慮;
- PWA (漸進式 Web 應用):通過 Service Worker 實現離線訪問和資源加載;
- 預渲染 (Prerendering):靜態頁面預生成 HTML,加速 SEO 和首屏加載;
15.SPA 首屏加載速度慢怎么解決
先計算 通過 DOMContentLoad 或者 performance 計算出首屏時間
// 方案一:
document.addEventListener('DOMContentLoaded', (event) => {console.log('first contentful painting');
});
// 方案二:
performance.getEntriesByName("first-contentful-paint")[0].startTime// performance.getEntriesByName("first-contentful-paint")[0]
// 會返回一個 PerformancePaintTiming的實例,結構如下:
{name: "first-contentful-paint",entryType: "paint",startTime: 507.80000002123415,duration: 0,
};
加載慢的原因:
- 網絡延遲問題
- 資源文件體積是否過大
- 資源是否重復發送請求去加載了
- 加載腳本的時候,渲染內容堵塞了
解決方案:
幾種常用的 SPA 首屏優化方式:
- 減小入口文件體積
- 靜態資源本地緩存:強緩存、協商緩存、Service Worker 離線緩存
- UI 架構按需加載:
- 圖片資源的壓縮:矢量字體、精靈圖
- 組件重新打包
- 開啟 GZip 壓縮:使用 compression-webpack-plugin
- 使用 SSR
減小入口文件體積:
- 路由懶加載,配置路由采用動態路由
- externals 加載外部 CDN 資源
16.Vue 實例掛載的過程中發生了什么?
- new Vue 的時候會調用 _init 方法
* 定義 $ set 、$ get、 $ delete 、$watch 等方法
* 定義 $ on、$ off 、$ emit 、等事件
* 定義 _update、$ forceUpdate、$ destroy 等生命周期 - 調用 $ mount 進行頁面的掛載
- 掛載的時候主要通過 mountComponent 方法
- 定義 updateComponment 更新函數
- 執行 render 生成虛擬 DOm
- _update 將虛擬 DOM 生成真實 DOM 結構,并且渲染到頁面中
17. v-if 和 v-for 不建議一起用
在 Vue 2.0 中 v-for 的優先級比 v-if 高 ,作用域同一個元素上,帶來性能的浪費(每次渲染都會先循環在進行條件判斷)
單在 Vue 3.0 中 v-if 的優先級永遠比 v-for 高
18. Vue 中給對象添加新屬性界面不刷新?
- Vue.set( target: Object | Array ,proprertyName/index : String| number, value: Number)
- Object.assign()
- $forcecUpdated()
小結: - 如果為對象添加少量的新屬性,可以直接采用 Vue.set()
- 如果需要為新對象添加大量的新屬性,則通過 Object.assign() 創建對象
- 如果實在是不知道怎么操作時候,可采用 $forceUpdate() 進行強制刷新(不建議)
18.Vue 中組件和插件有什么區別
插件:
- 添加全局方法或者屬性。如:vue-custom-element
- 添加全局資源:指令/ 過濾器 / 過渡 等。如 vue-touch
- 通過全局混入來添加一些組件選項。如 vue-router
- 添加 Vue 實例方法,通過把它們添加到 Vue.prototype 上實現
- 一個庫,提供自己的 API,同時提供上面提到的一個或者多個功能。如 vue-router
組件 | 插件 | |
---|---|---|
編寫形式 | vue 單文件,每一個 .vue 文件都可以看成一個組件 | vue 插件的實現應該暴露一個 install 方法,這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象 |
注冊形式 | 全局注冊和局部注冊 | 通過 Vue.use() 注冊 |
使用場景 | 用來構成你的 App 的業務模塊 | 對 Vue 的功能的增強或者補充 |
19. 說說對 vue 的 mixin 的理解,有什么應用場景?
局部混入 和 全局混入
合并策略:
- 替換型:props、methods、inject、computed
- 合并型:data,通過 set 方法進行合并和重新賦值
- 隊列型:全部生命周期和 watch,原理是將函數存入一個數組,然后正序遍歷執行
- 疊加型:component、directives、filters 通過原型鏈進行層層的疊加
20. SSR 解決了什么問題?
解決:
- 利于 SEO
- 首屏呈現渲染,提高首屏加載速度
缺點: - 復雜度:整個項目的復雜度
- 庫的支持性,代碼兼容
- 性能問題:內存消耗變大、緩存、降級
- 服務器負載變大
過程:
- 使用 ssr 不存在單例模式,每次用戶請求都會創建一個新的 vue 實例
- 使用 ssr 需要實現服務端首屏渲染和客戶端激活
- 服務端異步獲取數據 asyncData 可以分為首屏異步獲取和切換組件獲取
- 首屏異步獲取數據,在服務端預渲染的時候就應該已經完成
- 切換組件通過 mixin 混入,在 beforeMount 鉤子完成數據獲取
21.Vue.observable
Vue.observable 是 Vue.js 提供的一個工具函數,將普通 JavaScript 對象轉換為響應式對象。其核心作用是通過數據劫持(Vue 2.x 使用 Object.defineProperty,Vue 3.x 使用 Proxy)實現狀態變化的自動追蹤和視圖更新
// Vue 2.x
const state = Vue.observable({ count: 0 });
state.count++; // 直接修改原對象// Vue 3.x
import { reactive } from 'vue';
const state = reactive({ count: 0 }); // 等同于 Vue.observable
22.Vue 中 key 的原理
使用場景:
- 當我們在使用 v-for 時,需要給單元加上 key
- 用 +new Date() 生成的時間戳作為 key ,手動強制觸發重新渲染
key的作用:
key 是給每一個 vnode 的 唯一 id,也是 diff 的一種優化策略,可以根據 key,更準確,更快的找到對應的 vnode 節點
23.Vue 項目中有封裝過 axios ?
axios 是一個輕量的 HTTP 客戶端,基于 XMLHTTPRequest 服務來執行 HTTP 請求
特性:
- 從瀏覽器中創建 XMLHttpRequest
- 從 node.js 創建 http 請求
- 支持 Promise APL
- 攔截請求和響應
- 轉換請求數據和響應數據
- 取消請求
- 自動轉換 JSON 數據
- 客戶端支持 防御 XSRF
如何封裝:
- 封裝的同時,你需要和后端協商好一些約定,請求頭、狀態碼、請求超時時間…
- 設置接口請求前綴:根據開發、測試、生產環境的不同,前綴需要加以區分
- 請求頭:來實現一些具體的業務,也必須攜帶一些參數才可以請求
- 狀態碼:根據不同接口返回的不同 status,來執行不同的業務
- 請求方法:根據 get 、post 等方法進行一個再次封裝
- 請求攔截器:更加請求的請求頭設定,來決定哪些請求可以訪問
- 響應攔截器:根據后端返回的狀態碼進行判定執行不同的業務
24. Vue 項目的目錄結構
基本原則:
- 文件夾和文件夾內部語義一致性
- 單一入口/出口
- 就近原則,緊耦合的文件應該放到一起,且應以相對路徑引用
- 公共的文件應該以絕對路徑的方式從根目錄引用
- ./src 外的文件不應該被引入
25. vue 項目如何部署,404 問題
為什么在 history 模式下有問題?沒有刷新
為什么在 hash 模式下沒有問題?
解決方案: nginx 重定向