vue3面試題

(1)vue3編譯流程?

vue3的編譯分兩部分:編譯期和運(yùn)行期。編譯期間,先通過vue-loader把單文件組件編譯成符合原生JavaScript語法的模塊;運(yùn)行期間,會通過內(nèi)置的模板引擎對模板進(jìn)行編譯,生成render()函數(shù),且按照先父組件后子組件的順序?qū)δ0暹M(jìn)行編譯。

(2)vue3內(nèi)的宏是什么?和語法糖的區(qū)別?

按照vue3官方的說法,defineProps() 、defineEmits()、defineExpose()都是宏,它們使用形式上和函數(shù)調(diào)用差不多,區(qū)別是,第一,這些宏不需要通過模塊導(dǎo)入;第二,這些宏會在編譯期被編譯成符合JavaScript原生語法的代碼。語法糖也會被編譯成符合JavaScript原生語法的代碼,vue3官方對這兩者進(jìn)行區(qū)分是因?yàn)?,語法糖創(chuàng)建的是不曾有過的語法,而宏指的是給現(xiàn)有語法新的含義。

(3)<script setup/>的實(shí)現(xiàn)原理?

<script setup/>本質(zhì)是setup()函數(shù)的語法糖,vue-loader在編譯期間會把<script setup/>內(nèi)的代碼編譯成setup()函數(shù),把defineExpose()內(nèi)指定的變量編譯為setup()函數(shù)的返回值。

(4)組件實(shí)例是什么?

每個單文件組件都有一個組件實(shí)例,組件實(shí)例是用來存放組件狀態(tài)的,可以在setup()函數(shù)內(nèi),通過getCurrentInstance()獲取組件實(shí)例。

(5)啟動程序的時候,vue3單文件組件的初始化流程?

單文件組件由組件實(shí)例、相應(yīng)vnode、相應(yīng)node三部分組成。初始化的時候,先創(chuàng)建組件的實(shí)例;接著用父組件vnode初始化實(shí)例的props、attrs、slots成員;然后執(zhí)行setup()函數(shù);接著把模板編譯成render()函數(shù);接著創(chuàng)建vnode;如果當(dāng)前組件有子組件,則切換到子組件,重復(fù)上面的步驟;子組件都初始化完成后,把vnode同步到node上。

(6)createApp(),mount()做了什么工作?

程序在初始化的時候會依次調(diào)用createApp()和mount()函數(shù),createApp()負(fù)責(zé)執(zhí)行平臺相關(guān)的代碼,mount()負(fù)責(zé)執(zhí)行平臺無關(guān)的代碼。createApp()主要做了兩件事,第一,創(chuàng)建一個渲染器,它可用于把vdom轉(zhuǎn)化為平臺相關(guān)的界面代碼;第二,返回一個App實(shí)例。mount()的作用就是,創(chuàng)建組件實(shí)例、vdom、完成依賴收集、并通過渲染器把vdom渲染成平臺相關(guān)的界面代碼。

(7)組件的生命周期?

單個組件的生命周期:初始化階段,先執(zhí)行setup函數(shù)初始化實(shí)例,接著執(zhí)行onBeforeMount,最后執(zhí)行onMounted;運(yùn)行階段,先執(zhí)行onBeforeUpdate,再執(zhí)行onUpdated;關(guān)閉階段,先執(zhí)行onBeforeUnmount,再執(zhí)行onMounted。父子組件的生命周期:初始化階段,先執(zhí)行父組件的onBeforeMount,然后執(zhí)行子組件的onBeforeMount,接著執(zhí)行子組件的onMounted,最后執(zhí)行父組件的onMounted;運(yùn)行階段、關(guān)閉階段同理可推。

(8)什么是虛擬DOM?diff算法?

虛擬dom是用JavaScript語言描述的一個樹形結(jié)構(gòu),用于緩存發(fā)生變化的響應(yīng)式數(shù)據(jù),當(dāng)?shù)竭_(dá)下次刷新周期的時候,一次性把所有發(fā)生變化的數(shù)據(jù)同步到實(shí)際dom上。diff算法是同步vdom和dom數(shù)據(jù)的算法,采用就地復(fù)用的策略實(shí)現(xiàn)高效同步。

(9)任務(wù)調(diào)度系統(tǒng)?

vue3內(nèi)部維持了3類隊(duì)列:pre隊(duì)列——組件更新前置任務(wù)隊(duì)列;queue隊(duì)列——組件更新時的任務(wù)隊(duì)列;post隊(duì)列——組件更新后置任務(wù)隊(duì)列。vue3內(nèi)所有異步任務(wù)都會被推進(jìn)這些隊(duì)列,當(dāng)本次宏任務(wù)執(zhí)行結(jié)束的時候,會執(zhí)行一個名為flushJob的微任務(wù),該微任務(wù)會按照pre>queue>post的優(yōu)先級,依次執(zhí)行每個隊(duì)列中的函數(shù)。

(10)異步刷新是什么?怎么實(shí)現(xiàn)的?

異步刷新指的是在響應(yīng)式數(shù)據(jù)發(fā)生更改后,只更新vdom,不立即更新dom,當(dāng)下一個刷新周期到來的時候,次性把所有發(fā)生變化的數(shù)據(jù)同步到實(shí)際dom上。異步刷新是通過job隊(duì)列+Promise+diff算法實(shí)現(xiàn)的,當(dāng)響應(yīng)式數(shù)據(jù)發(fā)生更改時候,會立即更新vdom上的數(shù)據(jù),待下個刷新周期到來的前,開始執(zhí)行flushJob微任務(wù),flushJob會通過diff算法完成vdom和dom之間的數(shù)據(jù)同步。

(11)nextTick()的實(shí)現(xiàn)原理?

nextTick()作用是,讓回調(diào)函數(shù)在下一次刷新DOM的時候,具體來說在onUpdated后執(zhí)行。vue3內(nèi)的nextTick()是通過Promise實(shí)現(xiàn),當(dāng)微任務(wù)flushJob把Job隊(duì)列中的所有函數(shù)都執(zhí)行完了后,nextTick()回調(diào)會被推入微任務(wù)隊(duì)列,然后開始執(zhí)行。

(12)有哪三種Effect?作用?

vue3組件內(nèi)有3類Effect:computedEffect、watchEffect、renderEffect。正是通過這些Effect才實(shí)現(xiàn)數(shù)據(jù)可監(jiān)聽函數(shù)的綁定,其中computedEffect、watchEffect在setup()期間創(chuàng)建,而renderEffect在onBeforeMount和onMounted之間創(chuàng)建。

(13)watch(),watchEffect(),computed()的區(qū)別?

三者都用于實(shí)現(xiàn)數(shù)據(jù)和監(jiān)聽函數(shù)的綁定。原理上來說,三者的共同點(diǎn)是,都會在setup期間、即onBeforeMount之前,創(chuàng)建一個Effect對象,并執(zhí)行依賴收集函數(shù)進(jìn)行依賴收集。區(qū)別是,第一,watchEffect、computed的依賴收集函數(shù)和監(jiān)聽函數(shù)是同一個函數(shù),而watch的依賴收集函數(shù)和回調(diào)函數(shù)是兩個函數(shù),這就導(dǎo)致了watchEffect和computed參數(shù)中的監(jiān)聽函數(shù)會在程序初始化期間執(zhí)行一次,而watch參數(shù)中的監(jiān)聽函數(shù)默認(rèn)不會執(zhí)行;第二,computed參數(shù)中的監(jiān)聽函數(shù)在變量發(fā)生變化后立即執(zhí)行,watchEffect、watch參數(shù)中的監(jiān)聽函數(shù)執(zhí)行時機(jī)可由用戶指定,可以立即執(zhí)行,也可以異步執(zhí)行。

(14)響應(yīng)式編程的實(shí)現(xiàn)原理?

響應(yīng)式編程的核心是通過發(fā)布訂閱模式、Effect對象、重寫get函數(shù)實(shí)現(xiàn)的。發(fā)布訂閱模式實(shí)現(xiàn)數(shù)據(jù)和監(jiān)聽函數(shù)的綁定,Effect對象內(nèi)封裝有監(jiān)聽函數(shù)和調(diào)度策略,get函數(shù)則負(fù)責(zé)進(jìn)行依賴收集和返回數(shù)據(jù)。

(15)ref()和reactive()的區(qū)別?

兩者都用于實(shí)現(xiàn)響應(yīng)式變量,區(qū)別在于reactive()只可以封裝引用類型,ref()可以封裝任意類型;reactive()通過Proxy實(shí)現(xiàn),ref()通過類封裝,并重寫get/set實(shí)現(xiàn)。就目前而言,要訪問ref()封裝的變量,需要通過value函數(shù)獲取。

(16)ref()和ref(null)的區(qū)別?

ref()的作用是封裝普通數(shù)據(jù),實(shí)現(xiàn)響應(yīng)式數(shù)據(jù);ref(null)的作用是獲取子組件實(shí)例。

(17)attrs和props的區(qū)別?

attrs和props的作用都是,以模板屬性的形式,從父組件傳遞數(shù)據(jù)給子組件。區(qū)別是,子組件中獲取從父組件傳過來的props數(shù)據(jù),首先需要用defineProps()聲明,而獲取attrs數(shù)據(jù)不需要聲明。props的優(yōu)勢是增加了代碼可讀性,attrs的優(yōu)勢是傳值更靈活、代碼更簡潔。

(18)provide()和inject()實(shí)現(xiàn)原理?

在祖先組件里通過provide()提供的數(shù)據(jù),可以在任意子孫組件里通過inject()獲取。它是通過原型鏈實(shí)現(xiàn)的。

(19)emit()的實(shí)現(xiàn)原理?

emit()是通過發(fā)布訂閱模式實(shí)現(xiàn)的,子組件發(fā)送一個事件,父組件收到該事件會立即執(zhí)行相應(yīng)的函數(shù)。

(20)單向數(shù)據(jù)流的原因?

單向數(shù)據(jù)流指的是在 vue中約定,父組件傳遞給子組件的數(shù)據(jù)只能單向流動。也就是說,當(dāng)一個父組件將其數(shù)據(jù)傳遞給一個子組件時,子組件不能直接修改該數(shù)據(jù),而是需要通過向父組件發(fā)送事件來請求更改該數(shù)據(jù)。這種單向數(shù)據(jù)流的方式可以確保應(yīng)用程序的數(shù)據(jù)流向清晰明確,易于理解和維護(hù)。

(21)模板的編譯流程?在什么時候編譯?

模板會先被解析成AST對象,然后通過遍歷AST對象生成渲染函數(shù)。這個過程發(fā)生在setup()函數(shù)執(zhí)行結(jié)束后、onBeforeMount之前。

(22)組件注冊是什么?

若要在vue內(nèi)使用自定義組件,需要先注冊組件。組件注冊可以看作是一種聲明,用于告訴編譯器,某個標(biāo)簽名是組件。組件注冊分為局部注冊和全局注冊,全局注冊的組件可以在整個程序內(nèi)使用,局部注冊的組件只可以在特定組件內(nèi)使用。

(23)指令的實(shí)現(xiàn)原理?

vue3內(nèi)的指令是,本質(zhì)上是一系列鉤子函數(shù)的集合,可以為這些鉤子函數(shù)指定執(zhí)行時機(jī),包括:onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount和onUnmounted。

(24)各種指令的區(qū)別和作用?

v-show和v-if的區(qū)別:v-show=false的組件會被創(chuàng)建,但是不會顯示;v-if=false的組件不會被創(chuàng)建。v-on和v-bind的區(qū)別:v-on用于綁定事件和事件處理函數(shù);v-bind用于綁定變量。v-text,v-html和插值表達(dá)式的區(qū)別:插值表達(dá)式存在閃屏的問題,而v-text 、v-html不存在該問題;插值表達(dá)式和v-text都會直接以字符串的形式顯示html,v-html則可以渲染html標(biāo)簽對。

(25)v-for為什么要加key?

v-for為什么不能和v-if一起使用?v-for要加key是因?yàn)?,第一,vue的同步算法采用就地復(fù)用的策略,在沒有key值的情況下,diff算法認(rèn)為標(biāo)簽類型相同的元素可以進(jìn)行復(fù)用;有key值的情況下,diff算法認(rèn)為標(biāo)簽類型相同且key值相等的元素才可以復(fù)用。第二,vue只在v-model實(shí)現(xiàn)了數(shù)據(jù)雙向綁定,其它地方實(shí)現(xiàn)的都是單向綁定,<input/>框內(nèi)的文字發(fā)生變化,不會實(shí)時同步到數(shù)據(jù)上。在vue3中,v-if的優(yōu)先級高于v-for,導(dǎo)致v-if訪問不了v-for中的變量,因此不能把 v-if 和 v-for 同時用在同一個元素上。

(26)v-model的實(shí)現(xiàn)原理?

v-model實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定,它是通過響應(yīng)式數(shù)據(jù)+監(jiān)聽輸入框事件實(shí)現(xiàn)的。

(27)hook是什么?

hook是一種編程封裝思想,通過閉包實(shí)現(xiàn),早在ES6誕生之前,這種編程封裝思想在JavaScript中應(yīng)用廣泛,只不過在React17出現(xiàn)后,React官方把這種思想命名為hook,vue3借鑒react命名,也把這種封裝思想稱作hook。

(28)vue3插件是什么?

vue3內(nèi)的所謂的插件不是常規(guī)意義上的插件,而是指mount()前執(zhí)行的初始化函數(shù),vue插件通常用來為 vue 添加全局功能。vue3內(nèi)通過use()函數(shù)引入插件,use()的作用就是執(zhí)行參數(shù)對象內(nèi)的install()函數(shù)。

(29)什么是異步組件?

網(wǎng)頁的渲染流程一般分兩部,先從網(wǎng)絡(luò)加載網(wǎng)頁,然后渲染。異步組件指的是,首次加載和渲染網(wǎng)頁的時候,不從網(wǎng)絡(luò)上加載該組件對應(yīng)的JavaScript文件,而是等到需要顯示該組件的時候,再從網(wǎng)絡(luò)上加載該組件并渲染顯示出來。

(30)前端路由是什么?什么是路由懶加載?

路由能夠根據(jù)不同的URL地址返回給用戶不同的內(nèi)容或頁面,如果路由位于瀏覽器端,就是前端路由;如果路由位于服務(wù)器端,就是后端路由。對于SPA單頁應(yīng)用,打包構(gòu)建時,JavaScript包會變得非常大,會使得頁面首次加載的時間變長 。若將不同路由對應(yīng)的組件分割成不同的文件,然后當(dāng)路由被訪問的時候才從服務(wù)器加載對應(yīng)文件,這就是路由的懶加載。

以渲染html標(biāo)簽對。(25)v-for為什么要加key?v-for為什么不能和v-if一起使用?v-for要加key是因?yàn)?,第一,vue的同步算法采用就地復(fù)用的策略,在沒有key值的情況下,diff算法認(rèn)為標(biāo)簽類型相同的元素可以進(jìn)行復(fù)用;有key值的情況下,diff算法認(rèn)為標(biāo)簽類型相同且key值相等的元素才可以復(fù)用。第二,vue只在v-model實(shí)現(xiàn)了數(shù)據(jù)雙向綁定,其它地方實(shí)現(xiàn)的都是單向綁定,<input/>框內(nèi)的文字發(fā)生變化,不會實(shí)時同步到數(shù)據(jù)上。在vue3中,v-if的優(yōu)先級高于v-for,導(dǎo)致v-if訪問不了v-for中的變量,因此不能把 v-if 和 v-for 同時用在同一個元素上。

鏈接:https://zhuanlan.zhihu.com/p/637975012

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容