最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

【直接收藏】前端 VUE 高階面試題(三)

2023-08-25 10:56 作者:千鋒前端  | 我要投稿

86.說(shuō)說(shuō)vue生命周期,發(fā)送請(qǐng)求在生命周期的哪個(gè)階段,為什么不可以是beforeMount,mounted中

回答:

?1、vue的生命周期

1)、生命周期是什么? Vue 實(shí)例有一個(gè)完整的生命周期,也就是從開(kāi)始創(chuàng)建、初始化數(shù)據(jù)、編譯模版、掛載 Dom -> 渲染、更新 -> 渲染、卸載等一系列過(guò)程,我們稱這是 Vue 的生命周期。

2)、各個(gè)生命周期階段及其鉤子函數(shù)

vue的生命周期核心經(jīng)歷了四個(gè)階段,在四個(gè)階段的前后分別有兩個(gè)鉤子函數(shù)。

第一階段:數(shù)據(jù)掛載階段:把配置項(xiàng)data中的屬性,賦給了vue對(duì)象本身,并做了數(shù)據(jù)劫持。

該階段前后的兩個(gè)鉤子函數(shù):beforeCreate和created

第二階段:模板渲染階段:把vue對(duì)象的數(shù)據(jù)渲染到模板上。

該階段前后的兩個(gè)鉤子函數(shù):beforeMount和mounted

第三階段:組件更新階段:當(dāng)數(shù)據(jù)發(fā)送變化時(shí),組件會(huì)進(jìn)行重新渲染,所以,準(zhǔn)確的說(shuō)是,組件重新渲染階段。

該階段前后的兩個(gè)鉤子函數(shù):beforeUpdate和updated

第四階段:組件銷毀階段:組件銷毀。

該階段前后的兩個(gè)鉤子函數(shù):beforeDestroy和destroyed

視情況可以補(bǔ)充:

當(dāng)使用keep-alive包裹組件時(shí),會(huì)有組件激活和停用之說(shuō),這兩個(gè)鉤子函數(shù)分別是:activited和deactivated

?2、發(fā)送請(qǐng)求在生命周期的哪個(gè)階段,為什么不可以是beforeMount,mounted中。

(如果組件的初始數(shù)據(jù)來(lái)自后端)發(fā)送請(qǐng)求建議在鉤子函數(shù)created里,這個(gè)鉤子函數(shù)里是最快,也能有助于一致性。

? 為什么?

? 1)、為什么不能放在beforeCreate里?

? 因?yàn)椋?/p>

 一般來(lái)說(shuō),數(shù)據(jù)從后端返回回來(lái)后,都會(huì)賦給vue中的屬性(data掛載的),在beforeCreate鉤子函數(shù)里,data的數(shù)據(jù)還沒(méi)有掛載到vue對(duì)象本身上,所以,不能在這個(gè)鉤子函數(shù)里用。而created鉤子函數(shù)里,數(shù)據(jù)已經(jīng)掛載到vue對(duì)象了。

2)、為什么不可以是beforeMount,mounted中

因?yàn)椋?/p>

  ? 第一,在這兩個(gè)鉤子函數(shù)里,發(fā)送請(qǐng)求有點(diǎn)晚,會(huì)增加頁(yè)面loading的時(shí)間;

  ? 第二,vue的SSR不支持beforeMount 、mounted 鉤子函數(shù),所以,放在 created 中有助于一致性

87.兄弟和父子組件,在不能使用vuex的情況下有多少種方案,請(qǐng)列舉出來(lái)?

回答:

1、父子之間傳值:

  1)、父到子:props,子到父:$emit

  2)、$ref、$parent

  3)、事件總線(event-bus)

  4)、集中管理($root)


2、兄弟之間傳值:

  1)、事件總線(event-bus)

  2)、集中管理($root)

 3)、先 子到父(用事件),再 父到子(用props)

88.v-if和v-for可以同時(shí)使用嗎

回答:

  可以使用,但是,在循環(huán)時(shí),通過(guò)v-if只能拿到少部分?jǐn)?shù)據(jù)時(shí),建議不要使用。

  原因: v-for比v-if優(yōu)先級(jí)高,如果遍歷的數(shù)組元素個(gè)數(shù)比較多,但是滿足v-if條件比較少的情況下。會(huì)浪費(fèi)性能。而且,每次刷新頁(yè)面時(shí),都會(huì)執(zhí)行這樣性能不高的代碼。

 解決:可以在computed里循環(huán)數(shù)組,通過(guò)filter的方式,過(guò)濾出需要的數(shù)據(jù)。v-for直接循環(huán)計(jì)算屬性的結(jié)果(不用v-if)。而computed是有緩存的,所以,在原始數(shù)據(jù)沒(méi)有變化時(shí),不會(huì)多次過(guò)濾數(shù)據(jù),這樣,就提高了效率。

89.vue-cli怎么配置跨域

回答:

使用反向代理,vue-cli3+的項(xiàng)目里,新建(編輯)vue.config.js文件,(增加)配置代碼如下:

90.v-bind是用來(lái)干什么的

回答:

  ? ? v-bind指令是把標(biāo)簽的屬性處理成動(dòng)態(tài)的。分別可以把屬性名屬性值處理成vue里的屬性,常間的是屬性值處理成動(dòng)態(tài)的。

格式如下:

1、屬性值動(dòng)態(tài)綁定:v-bind:html屬性="數(shù)據(jù)" ?簡(jiǎn)寫 ? :html屬性="數(shù)據(jù)"` ?

示例:

2、 屬性名動(dòng)態(tài)綁定:v-bind:[屬性名]="數(shù)據(jù)"

此時(shí),屬性值也是動(dòng)態(tài)的

示例:

91.說(shuō)說(shuō)對(duì)插槽的理解

回答:

1、插槽的作用:

  ? ?插槽是用來(lái)處理組件的內(nèi)容的。插槽決定了組件的內(nèi)容放在組件模板的何處。插槽使用的是vue官方提供的組件<slot>來(lái)完成的。

2、vue中的插槽分為:

1)、單個(gè)插槽

  ?在組件中只有一個(gè)插槽時(shí),插槽不用起名字。默認(rèn)的名字是:default

示例:

2)、具名插槽

  ? 但組件中的插槽多于一個(gè)時(shí),就需要給組件起名字,用名字來(lái)區(qū)分不同的插槽。用官方組件slot的name屬性給插槽起名字

格式:

示例:

92.$nextTick理解 和定時(shí)器有什么區(qū)別 都是延時(shí)執(zhí)行

回答:

1、$nextTick理解:

  ? ?vue更新DOM時(shí),使用的是異步更新隊(duì)列。目的是提高性能,避免無(wú)效的重復(fù)的DOM更新。即:vue中更新數(shù)據(jù)后,并不會(huì)立即更新DOM,而是把數(shù)據(jù)引起的DOM更新放入到異步更新隊(duì)列里。等待下次事件循環(huán)(tick),并在兩個(gè)tick之間進(jìn)行UI渲染。

  ? ?按照這個(gè)思路,程序員就不能在更改數(shù)據(jù)后,立即獲取更新后的DOM,也不知道什么時(shí)候DOM能夠更新。基于此,vue提供了$nextTick函數(shù)。程序員只需要把 ?操作更新后DOM的代碼 ?放入到$nextTick的回調(diào)函數(shù)里。由$nextTick內(nèi)部,在更新完DOM后,調(diào)用回調(diào)函數(shù)。

示例:

2、$nextTick理解和定時(shí)器有什么區(qū)別

相同:都是延遲加載,都使用事件隊(duì)列

不同:

1)、定時(shí)器是下一個(gè)隊(duì)列的隊(duì)首。

2)、$nextTick()是放在當(dāng)前隊(duì)列的最后一個(gè)。$nextTick()的回調(diào)函數(shù)執(zhí)行要先于定時(shí)器。

93.event-bus是怎么用?

event-bus是事件總線,是借助一個(gè)全局的vue對(duì)象,來(lái)完成事件的綁定和事件的觸發(fā)。

當(dāng):我們需要把A組件的數(shù)據(jù)傳給B組件時(shí),在A、B兩個(gè)組件里都引入全局的vue對(duì)象。然后,在B組件里綁定事件,在A組件里觸發(fā)事件,就可以把A組件的數(shù)據(jù)傳給B組件了。

示例:

94.mounted與created的區(qū)別

回答:

mounted和created都是vue對(duì)象生命周期的鉤子函數(shù),執(zhí)行時(shí)機(jī)不同。

1、created 是在 data配置項(xiàng)的數(shù)據(jù)掛載到vue對(duì)象本身,會(huì)調(diào)用的鉤子函數(shù)。

?此時(shí),

 1)、用 ?this. ?的方式可以拿到data里的數(shù)據(jù)。

  2)、但是數(shù)據(jù)還沒(méi)有渲染到模板上。所以,訪問(wèn)dom時(shí),內(nèi)容還是原始的模板內(nèi)容。

2、mounted是在組件的模板初次渲染完畢后會(huì)調(diào)用的鉤子函數(shù)。

?此時(shí),

  ? data里的數(shù)據(jù)已經(jīng)渲染到模板上了。所以,訪問(wèn)dom時(shí),已經(jīng)和頁(yè)面上看到的效果一樣了。

95.v-model ? 原理 是什么

回答:

1、v-model指令的作用

?vue中的v-model指令是完成雙向綁定的,用在表單元素上。雙向綁定就是 M會(huì)影響V。V也會(huì)影響M。即:能將頁(yè)面上輸入的值同步更新到相關(guān)綁定的data屬性,也會(huì)在更新data綁定屬性時(shí)候,更新頁(yè)面上輸入控件的值。

2、v-model的原理 ? ? ?

  v-model指令是一個(gè)語(yǔ)法糖,是屬性綁定和事件的語(yǔ)法糖。vue會(huì)根據(jù)不同的表單元素使用不同的屬性和事件。

如下:

  • text 和 textarea 元素使用 value property 和 input 事件;

  • checkbox 和 radio 使用 checked property 和 change 事件;

  • select 字段將 value 作為 prop 并將 change 作為事件。

以文本框?yàn)槔饰鲈恚韵率谴a:

而,使用v-model來(lái)完成以上功能的代碼如下:


96.vue 的組件中的 data 配置為什么必須是函數(shù)(每個(gè)組件都是 vue 的實(shí)例)

vue 為了保證每個(gè)實(shí)例上的 data 數(shù)據(jù)的獨(dú)立性,規(guī)定了必須使用函數(shù),而不是對(duì)象。因?yàn)槭褂脤?duì)象的話,每個(gè)實(shí)例(組件)上使用的 data 數(shù)據(jù)是相互影響的,這當(dāng)然就不是我們想要的了。對(duì)象是對(duì)于內(nèi)存地址的引用,直接定義個(gè)對(duì)象的話組件之間都會(huì)使用這個(gè)對(duì)象,這樣會(huì)造成組件之間數(shù)據(jù)相互影響。而函數(shù)具有內(nèi)部作用域,可以解決這個(gè)問(wèn)題。

97.vue 中 computed 和 watch 的區(qū)別

  1. watch 和 computed 都是以 Vue 的依賴追蹤機(jī)制為基礎(chǔ)的,當(dāng)某一個(gè)依賴型數(shù)據(jù)(依賴型數(shù)據(jù):簡(jiǎn)單理解即放在 data 等對(duì)象下的實(shí)例數(shù)據(jù))發(fā)生變化的時(shí)候,所有依賴這個(gè)數(shù)據(jù)的相關(guān)數(shù)據(jù)會(huì)自動(dòng)發(fā)生變化,即自動(dòng)調(diào)用相關(guān)的函數(shù),來(lái)實(shí)現(xiàn)數(shù)據(jù)的變動(dòng)。當(dāng)依賴的值變化時(shí),在 watch 中,是可以做一些復(fù)雜的操作的,而 computed 中的依賴,僅僅是一個(gè)值依賴于另一個(gè)值,是值上的依賴。

  2. 應(yīng)用場(chǎng)景:computed:用于處理復(fù)雜的邏輯運(yùn)算;一個(gè)數(shù)據(jù)受一個(gè)或多個(gè)數(shù)據(jù)影響;用來(lái)處理 watch 和 methods 無(wú)法處理的,或處理起來(lái)不方便的情況。例如處理模板中的復(fù)雜表達(dá)式、購(gòu)物車?yán)锩娴纳唐窋?shù)量和總金額之間的變化關(guān)系等。 ?    watch:用來(lái)處理當(dāng)一個(gè)屬性發(fā)生變化時(shí),需要執(zhí)行某些具體的業(yè)務(wù)邏輯操作,或要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作;一個(gè)數(shù)據(jù)改變影響多個(gè)數(shù)據(jù)。例如用來(lái)監(jiān)控路由、inpurt 輸入框值的特殊處理等。

  3. 區(qū)別:

  • computed

    • 初始化顯示或者相關(guān)的 data、props 等屬性數(shù)據(jù)發(fā)生變化的時(shí)候調(diào)用;

    • 計(jì)算屬性不在 data 中,它是基于 data 或 props 中的數(shù)據(jù)通過(guò)計(jì)算得到的一個(gè)新值,這個(gè)新值根據(jù)已知值的變化而變化;

    • 在 computed 屬性對(duì)象中定義計(jì)算屬性的方法,和取 data 對(duì)象里的數(shù)據(jù)屬性一樣,以屬性訪問(wèn)的形式調(diào)用;

    • 如果 computed 屬性值是函數(shù),那么默認(rèn)會(huì)走 get 方法,必須要有一個(gè)返回值,函數(shù)的返回值就是屬性的屬性值;

    • computed 屬性值默認(rèn)會(huì)緩存計(jì)算結(jié)果,在重復(fù)的調(diào)用中,只要依賴數(shù)據(jù)不變,直接取緩存中的計(jì)算結(jié)果,只有依賴型數(shù)據(jù)發(fā)生改變,computed 才會(huì)重新計(jì)算;

    • 在 computed 中的,屬性都有一個(gè) get 和一個(gè) set 方法,當(dāng)數(shù)據(jù)變化時(shí),調(diào)用 set 方法。

  • watch

    • 主要用來(lái)監(jiān)聽(tīng)某些特定數(shù)據(jù)的變化,從而進(jìn)行某些具體的業(yè)務(wù)邏輯操作,可以看作是 computed 和 methods 的結(jié)合體;

    • 可以監(jiān)聽(tīng)的數(shù)據(jù)來(lái)源:data,props,computed 內(nèi)的數(shù)據(jù);

    • watch 支持異步;

    • 不支持緩存,監(jiān)聽(tīng)的數(shù)據(jù)改變,直接會(huì)觸發(fā)相應(yīng)的操作;

    • 監(jiān)聽(tīng)函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是最新的值,第二個(gè)參數(shù)是輸入之前的值,順序一定是新值,舊值。

98.vue 的生命周期?網(wǎng)絡(luò)請(qǐng)求為什么要掛載在 mounted 中?

  1. vue2 的生命周期

  • 初始化階段:

    • beforeCreate

    • created

  • 掛載階段

    • beforeMount

    • mounted

  • 更新階段

    • beforeUpdate

    • updated

  • 卸載階段

    • beforeDestroy

    • destroyed

  • 緩存組件相關(guān)

    • activated

    • deactivated

  • 處理錯(cuò)誤相關(guān)

    • errorCaptured

  1. vue3 的生命周期在 vue2 的基礎(chǔ)上新增了:

  • renderTracked:跟蹤虛擬 DOM 重新渲染時(shí)調(diào)用。鉤子接收 debugger event 作為參數(shù)。此事件告訴你哪個(gè)操作跟蹤了組件以及該操作的目標(biāo)對(duì)象和鍵。

  • renderTriggered:當(dāng)虛擬 DOM 重新渲染被觸發(fā)時(shí)調(diào)用。和 renderTracked 類似,接收 debugger event 作為參數(shù)。此事件告訴你是什么操作觸發(fā)了重新渲染,以及該操作的目標(biāo)對(duì)象和鍵。一共 13 個(gè)

  1. vue3 的組合 api 的生命周期移除了 beforeCreate 和 created,因?yàn)閯?chuàng)建時(shí)的事件可以在 setup 里面直接調(diào)用。其他的 11 個(gè)生命周期前面全部加上 on比如:mounted -> onMounted, beforeDestroy -> onDeforeDestroy

  2. 網(wǎng)絡(luò)請(qǐng)求為什么要掛載在 mounted 中?在 Created 生命周期里 Data 才生成,而請(qǐng)求返回的數(shù)據(jù)需要掛載在 data 上,所以 Created 里是可以初始化請(qǐng)求的,但是 Created 的這時(shí)候 DOM 還沒(méi)有初始化;Mounted 生命周期里 DOM 才初始化渲染完成。然而,請(qǐng)求是異步的,所以不會(huì)堵塞頁(yè)面渲染的主線程。所以請(qǐng)求放在 created 和 mounted 里面都是可行的。如果我們的請(qǐng)求不需要獲取/借助/依賴/改變 DOM,這時(shí)請(qǐng)求可以放在 Created。反之則可以放在 Mounted 里。這樣做會(huì)更加的安全,也能保證頁(yè)面不會(huì)閃爍。

99.vue 的指令,在項(xiàng)目中封裝了那些常用指令?

在 vue 中我們可以使用 Vue.directive()方法注冊(cè)全局指令。也可以只用 directives 選項(xiàng)注冊(cè)局部指令。

  • 輸入框防抖指令 v-debounce

  • 復(fù)制粘貼指令 v-copy

  • 長(zhǎng)按指令 v-longpress

  • 禁止表情及特殊字符 v-emoji

圖片懶加載 v-LazyLoad


權(quán)限校驗(yàn)指令 v-premission


  • 實(shí)現(xiàn)頁(yè)面水印 v-waterMarker

  • 拖拽指令 v-draggable

100.vue 的移動(dòng)端適配怎么做的,rem 怎么用的

vue 的移動(dòng)端適配我們可以參考 vant-ui 組件庫(kù)給我們提供的方案。使用 amfe-flexible(用于自動(dòng)定義跟字體大小)插件和 postcss-pxtorem(用于將 px 自動(dòng)轉(zhuǎn)成 rem)插件在 main.ts 里面 import "amfe-flexible"在根目錄新建 .postcssrc.js 文件

rem 是相對(duì)于跟字體的倍數(shù),如果我們整個(gè)項(xiàng)目都是用 rem 作為單位,那么當(dāng)我們做移動(dòng)端的響應(yīng)式的時(shí)候只需要去改變跟字體的大小就能做到適配。

101.后臺(tái)管理系統(tǒng)用戶驗(yàn)證權(quán)限

  1. 登錄用戶填寫完賬號(hào)和密碼后向服務(wù)端驗(yàn)證是否正確,登錄成功后,服務(wù)端會(huì)返回一個(gè) token(該 token 的是一個(gè)能唯一標(biāo)示用戶身份的一個(gè) key),之后我們將 token 存儲(chǔ)在本地 localstorage 之中,這樣下次打開(kāi)頁(yè)面或者刷新頁(yè)面的時(shí)候能記住用戶的登錄狀態(tài),不用再去登錄頁(yè)面重新登錄了。為了保證安全性,后臺(tái)所有 token 有效期(Expires/Max-Age)都是 Session,就是當(dāng)瀏覽器關(guān)閉了就丟失了。重新打開(kāi)瀏覽器都需要重新登錄驗(yàn)證,后端也會(huì)在每周固定一個(gè)時(shí)間點(diǎn)重新刷新 token,讓后臺(tái)用戶全部重新登錄一次,確保后臺(tái)用戶不會(huì)因?yàn)殡娔X遺失或者其它原因被人隨意使用賬號(hào)。

  2. 攔截路由進(jìn)行判斷頁(yè)面會(huì)先從 localstorage 中查看是否存有 token,沒(méi)有,就走一遍上一部分的流程重新登錄,如果有 token,就會(huì)把這個(gè) token 返給后端去拉取 user_info,保證用戶信息是最新的。當(dāng)然如果是做了單點(diǎn)登錄得的的話,用戶信息存儲(chǔ)在本地也是可以的。當(dāng)你一臺(tái)電腦登錄時(shí),另一臺(tái)會(huì)被提下線,所以總會(huì)重新登錄獲取最新的內(nèi)容。

  3. 權(quán)限控制前端會(huì)有一份路由表,它表示了每一個(gè)路由可訪問(wèn)的權(quán)限。當(dāng)用戶登錄之后,通過(guò) token 獲取用戶的 role ,動(dòng)態(tài)根據(jù)用戶的 role 算出其對(duì)應(yīng)有權(quán)限的路由,再通過(guò) router.addRoutes 動(dòng)態(tài)掛載路由。但這些控制都只是頁(yè)面級(jí)的,說(shuō)白了前端再怎么做權(quán)限控制都不是絕對(duì)安全的,后端的權(quán)限驗(yàn)證是逃不掉的。前端控制頁(yè)面級(jí)的權(quán)限,不同權(quán)限的用戶顯示不同的側(cè)邊欄和限制其所能進(jìn)入的頁(yè)面(也做了少許按鈕級(jí)別的權(quán)限控制),后端則會(huì)驗(yàn)證每一個(gè)涉及請(qǐng)求的操作,驗(yàn)證其是否有該操作的權(quán)限,每一個(gè)后臺(tái)的請(qǐng)求不管是 get 還是 post 都會(huì)讓前端在請(qǐng)求 header 里面攜帶用戶的 token,后端會(huì)根據(jù)該 token 來(lái)驗(yàn)證用戶是否有權(quán)限執(zhí)行該操作。若沒(méi)有權(quán)限則拋出一個(gè)對(duì)應(yīng)的狀態(tài)碼,前端檢測(cè)到該狀態(tài)碼,做出相對(duì)應(yīng)的操作。

  4. 利用 vuex 管理路由表,根據(jù) vuex 中可訪問(wèn)的路由渲染側(cè)邊欄組件。

  • 創(chuàng)建 vue 實(shí)例的時(shí)候?qū)?vue-router 掛載,但這個(gè)時(shí)候 vue-router 掛載一些登錄或者不用權(quán)限的公用的頁(yè)面。

  • 當(dāng)用戶登錄后,獲取用 role,將 role 和路由表每個(gè)頁(yè)面的需要的權(quán)限作比較,生成最終用戶可訪問(wèn)的路由表。

  • 調(diào)用 router.addRoutes(store.getters.addRouters)添加用戶可訪問(wèn)的路由。

  • 使用 vuex 管理路由表,根據(jù) vuex 中可訪問(wèn)的路由渲染側(cè)邊欄組件。

102.vuex 做數(shù)據(jù)請(qǐng)求刷新頁(yè)面,數(shù)據(jù)可能會(huì)發(fā)生丟失這個(gè)問(wèn)題怎么解決

因?yàn)?store 里的數(shù)據(jù)是保存在運(yùn)行內(nèi)存中的,當(dāng)頁(yè)面刷新時(shí),頁(yè)面會(huì)重新加載 vue 實(shí)例,store 里面的數(shù)據(jù)就會(huì)被重新賦值初始化。所以我們可以在修改 store 的數(shù)據(jù)同時(shí)將數(shù)據(jù)再存一份到本地存儲(chǔ)(localStorage 或者 sessionStorage),本地存儲(chǔ)的內(nèi)容是存在瀏覽器里面的,不會(huì)因?yàn)樗⑿露鴣G失。我們也可以用過(guò)比如 vuex-persistedstate 這樣的第三方包來(lái)幫助我們做 vuex 的持久化數(shù)據(jù)。

103.vue2 和 vue3 兩者的具體的區(qū)別有哪些,請(qǐng)一一例舉出來(lái)

  1. 源碼使用 ts 重寫現(xiàn)如今 typescript 異?;鸨?,它的崛起是有原因的,因?yàn)閷?duì)于規(guī)模很大的項(xiàng)目,沒(méi)有類型聲明,后期維護(hù)和代碼的閱讀都是頭疼的事情,所以廣大碼農(nóng)迫切的需要 vue 能完美支持 ts。vue2 用的是 Facebook 的 Flow 做類型檢查,但是因?yàn)槟承┣闆r下推斷有問(wèn)題,所以 vue3 使用 typescript 進(jìn)行了源碼的重寫。一個(gè)是為了更好的類型檢查,另一個(gè)是擁抱 ts。

  2. 使用 proxy 代替 defineProperty我們知道 vue2.x 雙向綁定的核心是 Object.defineProperty(),所以導(dǎo)致 vue 對(duì)數(shù)組對(duì)象的深層監(jiān)聽(tīng)無(wú)法實(shí)現(xiàn)。所以 vue3 使用 proxy 對(duì)雙向綁定進(jìn)行了重寫。Proxy 可以對(duì)整體進(jìn)行監(jiān)聽(tīng),不需要關(guān)心里面有什么屬性,而且 Proxy 的配置項(xiàng)有 13 種,可以做更細(xì)致的事情,這是之前的 defineProperty 無(wú)法達(dá)到的。

  3. Diff 算法的提升vue3 在 vue2 的 diff 算法的基礎(chǔ)上增加了靜態(tài)標(biāo)記,元素提升和事件緩存等優(yōu)化。使得速度更快。

  4. 打包體積變化vue2 官方說(shuō)的運(yùn)行時(shí)打包師 23k,但這只是沒(méi)安裝依賴的時(shí)候,隨著依賴包和框架特性的增多,有時(shí)候不必要的,未使用的代碼文件都被打包了進(jìn)去,所以后期項(xiàng)目大了,打包文件會(huì)特別多還很大。在 Vue 3 中,我們通過(guò)將大多數(shù)全局 API 和內(nèi)部幫助程序移動(dòng)到 Javascript 的 module.exports 屬性上實(shí)現(xiàn)這一點(diǎn)。這允許現(xiàn)代模式下的 module bundler 能夠靜態(tài)地分析模塊依賴關(guān)系,并刪除與未使用的 module.exports 屬性相關(guān)的代碼。模板編譯器還生成了對(duì)樹抖動(dòng)友好的代碼,只有在模板中實(shí)際使用某個(gè)特性時(shí),該代碼才導(dǎo)入該特性的幫助程序。盡管增加了許多新特性,但 Vue 3 被壓縮后的基線大小約為 10 KB,不到 Vue 2 的一半。

  5. 其他 Api 和功能的改動(dòng)

  • Global API

  • 模板指令

  • 組件

  • 渲染函數(shù)

  • vue-cli 從 v4.5.0 開(kāi)始提供 Vue 3 預(yù)設(shè)

  • Vue Router 4.0 提供了 Vue 3 支持,并有許多突破性的變化

  • Vuex 4.0 提供了 Vue 3 支持,其 API 與 2.x 基本相同

  1. 組件基本結(jié)構(gòu)

在創(chuàng)建組件的時(shí)候我們不必在寫唯一的根元素。移除了 vue2 中的 filters。

  1. 生命周期的區(qū)別

新增了 renderTracked 和 renderTriggered 兩個(gè)生命周期。

  1. 增加了組合 api

我們可以使用 setup 函數(shù)來(lái)使用類似 react 的自定義 hooks 的功能,主要解決邏輯關(guān)注點(diǎn)分離的問(wèn)題。

104.vue 操作虛擬 DOM 有什么優(yōu)異的地方?他不是還多做了一層虛擬 DOM,為什么比原生操作 DOM 還快

我們有必要先了解下模板轉(zhuǎn)換成視圖的過(guò)程整個(gè)過(guò)程:

  • Vue.js 通過(guò)編譯將 template 模板轉(zhuǎn)換成渲染函數(shù)(render ) ,執(zhí)行渲染函數(shù)就可以得到一個(gè)虛擬節(jié)點(diǎn)樹。

  • 在對(duì) Model 進(jìn)行操作的時(shí)候,會(huì)觸發(fā)對(duì)應(yīng) Dep 中的 Watcher 對(duì)象。Watcher 對(duì)象會(huì)調(diào)用對(duì)應(yīng)的 update 來(lái)修改視圖。這個(gè)過(guò)程主要是將新舊虛擬節(jié)點(diǎn)進(jìn)行差異對(duì)比,然后根據(jù)對(duì)比結(jié)果進(jìn)行 DOM 操作來(lái)更新視圖。

簡(jiǎn)單點(diǎn)講,在 Vue 的底層實(shí)現(xiàn)上,Vue 將模板編譯成虛擬 DOM 渲染函數(shù)。結(jié)合 Vue 自帶的響應(yīng)系統(tǒng),在狀態(tài)改變時(shí),Vue 能夠智能地計(jì)算出重新渲染組件的最小代價(jià)并應(yīng)到 DOM 操作上。

那么 vue 操作虛擬 DOM 有什么優(yōu)異的地方呢?

  • 具備跨平臺(tái)的優(yōu)勢(shì)由于 Virtual DOM 是以 JavaScript 對(duì)象為基礎(chǔ)而不依賴真實(shí)平臺(tái)環(huán)境,所以使它具有了跨平臺(tái)的能力,比如說(shuō)瀏覽器平臺(tái)、Weex、Node 等。

  • 操作 DOM 慢,js 運(yùn)行效率高。我們可以將 DOM 對(duì)比操作放在 JS 層,提高效率。因?yàn)?DOM 操作的執(zhí)行速度遠(yuǎn)不如 Javascript 的運(yùn)算速度快,因此,把大量的 DOM 操作搬運(yùn)到 Javascript 中,運(yùn)用 patching 算法來(lái)計(jì)算出真正需要更新的節(jié)點(diǎn),最大限度地減少 DOM 操作,從而顯著提高性能。Virtual DOM 本質(zhì)上就是在 JS 和 DOM 之間做了一個(gè)緩存??梢灶惐?CPU 和硬盤,既然硬盤這么慢,我們就在它們之間加個(gè)緩存:既然 DOM 這么慢,我們就在它們 JS 和 DOM 之間加個(gè)緩存。CPU(JS)只操作內(nèi)存(Virtual DOM),最后的時(shí)候再把變更寫入硬盤(DOM)

  • 提升渲染性能Virtual DOM 的優(yōu)勢(shì)不在于單次的操作,而是在大量、頻繁的數(shù)據(jù)更新下,能夠?qū)σ晥D進(jìn)行合理、高效的更新。為了實(shí)現(xiàn)高效的 DOM 操作,一套高效的虛擬 DOM diff 算法顯得很有必要。我們通過(guò) patch 的核心—-diff 算法,找出本次 DOM 需要更新的節(jié)點(diǎn)來(lái)更新,其他的不更新。比如修改某個(gè) model 100 次,從 1 加到 100,那么有了 Virtual DOM 的緩存之后,只會(huì)把最后一次修改 patch 到 view 上。那 diff 算法的實(shí)現(xiàn)過(guò)程是怎樣的?

那么為什么比原生操作 DOM 還快呢?首先我們每次操作 dom 的時(shí)候,都會(huì)去執(zhí)行瀏覽器的那 5 個(gè)步驟,尤其是當(dāng)大量循環(huán)的時(shí)候,每次循環(huán)完都不知道后面還要不要修改,所以每次都要去重復(fù)這個(gè)過(guò)程,引發(fā)不必要的渲染。但是在實(shí)際開(kāi)發(fā)過(guò)程中,我們會(huì)發(fā)現(xiàn)虛擬 dom 并沒(méi)有比真實(shí) dom 更快。這個(gè)問(wèn)題尤雨溪在知乎上面有過(guò)回答:這是一個(gè)性能 vs. 可維護(hù)性的取舍??蚣艿囊饬x在于為你掩蓋底層的 DOM 操作,讓你用更聲明式的方式來(lái)描述你的目的,從而讓你的代碼更容易維護(hù)。沒(méi)有任何框架可以比純手動(dòng)的優(yōu)化 DOM 操作更快,因?yàn)榭蚣艿?DOM 操作層需要應(yīng)對(duì)任何上層 API 可能產(chǎn)生的操作,它的實(shí)現(xiàn)必須是普適的。針對(duì)任何一個(gè) benchmark,我都可以寫出比任何框架更快的手動(dòng)優(yōu)化,但是那有什么意義呢?在構(gòu)建一個(gè)實(shí)際應(yīng)用的時(shí)候,你難道為每一個(gè)地方都去做手動(dòng)優(yōu)化嗎?出于可維護(hù)性的考慮,這顯然不可能??蚣芙o你的保證是,你在不需要手動(dòng)優(yōu)化的情況下,我依然可以給你提供過(guò)得去的性能。

105.token 過(guò)期你是如何來(lái)進(jìn)行處理,有沒(méi)有弄過(guò) token 續(xù)期

在開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到使用 token,token 的作用是要驗(yàn)證用戶是否處于登錄狀態(tài),所以要請(qǐng)求一些只有登錄狀態(tài)才能查看的資源的時(shí)候,我們需要攜帶 token。

一般的后端接口設(shè)置的 token 是有時(shí)效的,超時(shí)后就會(huì)失效,失效之后的處理策略一般會(huì)做兩種處理:

  • 一種是直接跳轉(zhuǎn)到登錄頁(yè)面,重新登錄。

  • 另外一種如果返回 token 失效的信息,自動(dòng)去刷新 token,然后繼續(xù)完成未完成的請(qǐng)求操作。

106.vue底層實(shí)現(xiàn)原理

  • 使用 Object.defineProperty 劫持 data上的數(shù)據(jù)。

  • Vue2.0通過(guò)設(shè)定對(duì)象屬性的 setter/getter 方法來(lái)監(jiān)聽(tīng)數(shù)據(jù)的變化,通過(guò)getter進(jìn)行依賴收集,而每個(gè)setter方法就是一個(gè)觀察者,在數(shù)據(jù)變更的時(shí)候通知訂閱者更新視圖。

107.Vue的生命周期,created與mounted的區(qū)別

1、created

表示組件實(shí)例已經(jīng)完全創(chuàng)建,data數(shù)據(jù)已經(jīng)被 Object.defineProperty 劫持完成,屬性也綁定成功,但真實(shí)dom還沒(méi)有生成,$el還不可用。

2、mounted

el選項(xiàng)所對(duì)應(yīng)的視圖節(jié)點(diǎn)已經(jīng)被新創(chuàng)建的 vm.$el 替換,并掛載到實(shí)例上去了。此時(shí)響應(yīng)式數(shù)據(jù)都已經(jīng)完成了渲染。

108.用vue寫了商城,從列表頁(yè)點(diǎn)進(jìn)詳情頁(yè),從詳情頁(yè)退出來(lái)的時(shí)候,怎么保持進(jìn)入詳情頁(yè)之前的頁(yè)面卷動(dòng)值。

使用 <keep-alive>對(duì)列表頁(yè)面進(jìn)行包裹,被包裹的列表頁(yè)面就有了activated、deactivated這兩個(gè)生命周期。在離開(kāi)列表頁(yè)面時(shí),在deactivated中記錄頁(yè)面的滾動(dòng)條位置。再次進(jìn)入列表頁(yè)面時(shí),在activated中使用 this.$el.scrollTop 把頁(yè)面滾動(dòng)到離開(kāi)時(shí)所記錄的位置。

109.說(shuō)說(shuō)你對(duì)vue的理解

  • vue是數(shù)據(jù)驅(qū)動(dòng)的MVVM框架,相比傳統(tǒng)的DOM庫(kù),vue有一層虛擬DOM。每當(dāng)數(shù)據(jù)發(fā)生更新時(shí),會(huì)觸發(fā)虛擬DOM進(jìn)行diff運(yùn)算,找出最小的變化節(jié)點(diǎn),大大地節(jié)省了DOM操作性能。

  • vue是組件化的,在單頁(yè)面應(yīng)用程序中,每一個(gè)組件相當(dāng)于是一塊積木,搭建起龐大的應(yīng)用系統(tǒng)。組件,可以理解成更大粒度的“HTML元素”,有利于快速開(kāi)發(fā)、組件的高效復(fù)用。

  • vue有一整套指令,大大地降低了開(kāi)發(fā)者的開(kāi)發(fā)難度,提升了開(kāi)發(fā)效率。

  • 雖然vue有諸多優(yōu)點(diǎn),但仍然有一些缺陷,比如復(fù)雜的業(yè)務(wù)頁(yè)面通常過(guò)長(zhǎng),data、methods、computed、watch對(duì)應(yīng)的數(shù)據(jù)和邏輯交織在一起,難以維護(hù)。

110.說(shuō)說(shuō)對(duì)虛擬DOM的理解

  • 在vue中,虛擬DOM本質(zhì)上就是一個(gè)固定格式的JSON數(shù)據(jù),它用于描述真實(shí)的DOM結(jié)構(gòu),并使用各種不同flag標(biāo)記出動(dòng)態(tài)的DOM節(jié)點(diǎn)。

  • 虛擬DOM數(shù)據(jù)保存在應(yīng)用程序?qū)?yīng)的內(nèi)存結(jié)構(gòu)中,擁有更快的數(shù)據(jù)交換速度。

  • 每當(dāng)有數(shù)據(jù)發(fā)生變化時(shí),就會(huì)生成新的虛擬DOM,進(jìn)一步發(fā)生diff運(yùn)算,找出最小臟節(jié)點(diǎn),減少不必要的DOM開(kāi)銷,這也是vue擁有更好的性能的根本原因。

111.說(shuō)說(shuō)provide的用法

  • 在父級(jí)組件中,使用provide選項(xiàng)向vue組件樹中“提供數(shù)據(jù)”,其語(yǔ)法是:provide:{a: 1}

  • 在后代子級(jí)組件中,使用 inject選項(xiàng)從vue組件中“取出數(shù)據(jù)”,其語(yǔ)法是:inject: ['a']

112.說(shuō)一下element ui遇到過(guò)的坑

  1. 表單設(shè)置觸發(fā)事件為blur,但是ctrl+A全選以后再刪除時(shí)又觸發(fā)了change事件,并提示一個(gè)原始報(bào)錯(cuò)

    • 解決方案:trigger設(shè)置成trigger: ['blur', 'change']

  2. 使用el-dialog 遮罩層把顯示內(nèi)容遮住了

    • 原因:Dialog 的外層布局的 position 值為 fixed, absolute, relative 三者之一時(shí),就會(huì)出現(xiàn)被蒙板遮住的情況。

    • 解決方法:v-bind:modal-append-to-body="false"

  3. 使用el-select 不能繼承父元素的寬度

    • 原因:el-select 本身是 ?inline-block

    • 解決辦法:手動(dòng)設(shè)置el-select的寬度

113.怎么修改element ui動(dòng)態(tài)組件的樣式

要修改elementUI組件的樣式,可以采用以下兩種方式

1.全局樣式

通過(guò)選擇權(quán)重覆蓋elementUI組件的樣式,如修改復(fù)選框?yàn)閳A角:

但這種方式為全局樣式,會(huì)影響頁(yè)面中所有復(fù)選框,如果不希望影響其它頁(yè)面的樣式,可以采用第二中方式

2.局部樣式

但如果僅僅是設(shè)置了scoped屬性,樣式無(wú)法生效,原因是以上樣式會(huì)被編譯成屬性選擇器,而elementUI組件內(nèi)部的結(jié)構(gòu)卻無(wú)法添加該html屬性,以上樣式被編譯成如下代碼:

解決方案也很簡(jiǎn)單,只需在選擇器中要添加>>>即可


如果是sass或less編寫的樣式,還可以使用/deep/


以上寫法樣式都會(huì)編譯成以下樣式:


  1. 所以elementUI中的樣式就能成功覆蓋

114.vue和react中的key值主要用來(lái)干什么

key是虛擬DOM對(duì)象的標(biāo)識(shí),在更新顯示時(shí)key起著極其重要的作用,vue和react都是采用diff算法來(lái)對(duì)比新舊虛擬節(jié)點(diǎn),而key的作用是為了在執(zhí)行 diff算法 的時(shí)候,更快更準(zhǔn)確地找到對(duì)應(yīng)的虛擬節(jié)點(diǎn),從而提高diff速度。

115.route和router區(qū)別

routerouter 是vue-router中經(jīng)常會(huì)操作的兩個(gè)對(duì)象, route表示當(dāng)前的路由信息對(duì)象,包含了當(dāng)前 URL 解析得到的信息,包含當(dāng)前的路徑、參數(shù)、query對(duì)象等,一般用于獲取跳轉(zhuǎn)時(shí)傳入的參數(shù)。router對(duì)象是全局路由的實(shí)例,是router構(gòu)造方法的實(shí)例,一般用戶路由跳轉(zhuǎn),如router.push()、router.replace() 等方法

116.vue和react相對(duì)于傳統(tǒng)的有什么好處,性能優(yōu)點(diǎn)

  1. 組件化開(kāi)發(fā),開(kāi)發(fā)效率更高

    React與Vue都鼓勵(lì)使用組件化開(kāi)發(fā)。這本質(zhì)上是建議你將你的應(yīng)用分拆成一個(gè)個(gè)功能明確的模塊,每個(gè)模塊之間可以通過(guò)特定的方式進(jìn)行關(guān)聯(lián)。這樣可以更好的管理功能模塊與復(fù)用,在團(tuán)隊(duì)項(xiàng)目中也能更好的分工協(xié)作

  2. VirtualDOM,性能更高

    對(duì)真實(shí)DOM的操作很慢,所以Vue和React都實(shí)現(xiàn)了虛擬DOM,用戶對(duì)數(shù)據(jù)的修改首先反映到虛擬DOM上,而不是直接操作真實(shí)DOM,然后在虛擬DOM環(huán)節(jié)進(jìn)行優(yōu)化,比如只修改差異項(xiàng),對(duì)虛擬 DOM 進(jìn)行頻繁修改時(shí)進(jìn)行合并,然后一次性修改真實(shí) DOM 中需要改的部分,最后在真實(shí) DOM 中進(jìn)行排版與重繪,減少過(guò)多DOM節(jié)點(diǎn)排版與重繪損耗等

  3. 數(shù)據(jù)和結(jié)構(gòu)的分離

  4. 雙向數(shù)據(jù)綁定

    Vue可以通過(guò)v-model指令實(shí)現(xiàn),react可通過(guò)單向綁定+事件來(lái)實(shí)現(xiàn)

  5. 強(qiáng)大的周邊生態(tài)

    Vue和React都有著強(qiáng)大的生態(tài),比如路由、狀態(tài)管理、腳手架等,用戶可以根據(jù)需求自行選擇,不需要重復(fù)造輪子

117.虛擬DOM實(shí)現(xiàn)原理

我們先來(lái)看看瀏覽器渲染一個(gè)頁(yè)面的過(guò)和,大概需要以下5個(gè)步驟

  1. 解析HTML元素,構(gòu)建DOM樹

  2. 解析CSS,生成頁(yè)面CSS規(guī)則樹(Style Rules)

  3. 將DOM樹和CSS規(guī)則樹進(jìn)行關(guān)聯(lián),生成render樹

  4. 布局(layout/reflow):瀏覽器設(shè)定Render樹中的每個(gè)節(jié)點(diǎn)在屏幕上的位置與尺寸

  5. 繪制Render樹:繪制頁(yè)面像素信息到屏幕上

眾所周知,一個(gè)頁(yè)面在瀏覽器中最大的開(kāi)銷就是DOM節(jié)點(diǎn)操作,頁(yè)面的性能問(wèn)題大多數(shù)是DOM操作引起的,當(dāng)我們用原生js 或jquery這樣的庫(kù)去操作DOM時(shí),瀏覽器會(huì)從構(gòu)建DOM樹開(kāi)始執(zhí)行完以上整個(gè)流程,所以頻繁操作DOM會(huì)引起不需要的計(jì)算、重排與重繪,從而導(dǎo)致頁(yè)面卡頓,影響用戶體驗(yàn)

所以減少DOM的操作能達(dá)到性能優(yōu)化的目的,事實(shí)上,虛擬DOM就是這么做的,虛擬DOM(VirtualDOM) 的實(shí)現(xiàn)原理主要包括以下 3 部分:

  1. 用 JavaScript 對(duì)象模擬真實(shí) DOM 樹,對(duì)真實(shí) DOM 進(jìn)行抽象

  2. diff 算法 — 比較新舊兩個(gè)虛擬DOM,得到差異對(duì)象

  3. pach 算法 — 將差異對(duì)象應(yīng)用到真實(shí) DOM 樹

Virtual DOM 本質(zhì)上就是一個(gè)javascript對(duì)象,數(shù)據(jù)的修改會(huì)生成一個(gè)新的虛擬DOM(一個(gè)新的javascript對(duì)象),然后與舊的虛擬DOM進(jìn)行對(duì)比,得到兩個(gè)對(duì)象的差異項(xiàng),最后只更新差異對(duì)象中的內(nèi)容到真實(shí)DOM,這樣能做到最少限度地修改真實(shí)DOM,從而實(shí)現(xiàn)性能優(yōu)化

118.如何實(shí)現(xiàn)角色權(quán)限分配

在開(kāi)發(fā)中后臺(tái)應(yīng)用過(guò)程中或多或少都會(huì)涉及到一個(gè)問(wèn)題:權(quán)限,簡(jiǎn)單地說(shuō)就是讓不同的用戶在系統(tǒng)中擁有不同的操作能力。

但在實(shí)際應(yīng)用中我們一般不直接將權(quán)限賦予在用戶身上,因?yàn)檫@樣操作對(duì)有大量用戶的系統(tǒng)來(lái)說(shuō)過(guò)于繁瑣,所以我們一般基于RBAC(Role-Based Access Control)權(quán)限模型,引入角色的概念,通過(guò)角色的媒介過(guò)渡,先將權(quán)限賦予在角色上,再關(guān)聯(lián)相應(yīng)的用戶,對(duì)應(yīng)的用戶就繼承了角色的權(quán)限

用戶與角色,角色與權(quán)限都是多對(duì)多的關(guān)系

引入角色媒介的優(yōu)點(diǎn):

  1. 實(shí)現(xiàn)了用戶與權(quán)限的解耦

  2. 提高了權(quán)限配置的效率

  3. 降低了后期維護(hù)的成本

119.雙向數(shù)據(jù)綁定和單向數(shù)據(jù)流的優(yōu)缺點(diǎn)

所謂數(shù)據(jù)綁定,就是指View層和Model層之間的映射關(guān)系。

  • 單向數(shù)據(jù)綁定:Model的更新會(huì)觸發(fā)View的更新,而View的更新不會(huì)觸發(fā)Model的更新,它們的作用是單向的。

    優(yōu)點(diǎn):所有狀態(tài)變化都可以被記錄、跟蹤,狀態(tài)變化通過(guò)手動(dòng)調(diào)用觸發(fā),源頭易追溯。

    缺點(diǎn):會(huì)有很多類似的樣板代碼,代碼量會(huì)相應(yīng)的上升。


  • 雙向數(shù)據(jù)綁定:Model的更新會(huì)觸發(fā)View的更新,View的更新也會(huì)觸發(fā)Model的更新,它們的作用是相互的。

    優(yōu)點(diǎn):在操作表單時(shí)使用v-model方便簡(jiǎn)單,可以省略繁瑣或重復(fù)的onChange事件去處理每個(gè)表單數(shù)據(jù)的變化(減少代碼量)。

    缺點(diǎn):屬于暗箱操作,無(wú)法很好的追蹤雙向綁定的數(shù)據(jù)的變化。

120.Vue是如何實(shí)現(xiàn)雙向綁定的?

Vue的雙向數(shù)據(jù)綁定是通過(guò)數(shù)據(jù)劫持結(jié)合發(fā)布者訂閱者模式來(lái)實(shí)現(xiàn)的 要實(shí)現(xiàn)這種雙向數(shù)據(jù)綁定,必要的條件有:

  1. 實(shí)現(xiàn)一個(gè)數(shù)據(jù)監(jiān)聽(tīng)器Observer,能夠?qū)?shù)據(jù)對(duì)象的所有屬性進(jìn)行監(jiān)聽(tīng),如有變動(dòng)可拿到最新值并通知訂閱者

  2. 實(shí)現(xiàn)一個(gè)指令解析器Compile,對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描和解析,根據(jù)指令模板替換數(shù)據(jù),以及綁定相應(yīng)的更新函數(shù)

  3. 實(shí)現(xiàn)一個(gè)Watcher,作為連接Observer和Compile的橋梁,能夠訂閱并收到每個(gè)屬性變動(dòng)的通知,執(zhí)行指令綁定的相應(yīng)回調(diào)函數(shù),從而更新視圖

  4. MVVM入口函數(shù),整合以上三者

補(bǔ)充回答

在new Vue的時(shí)候,在 Observer 中通過(guò) Object.defineProperty() 達(dá)到數(shù)據(jù)劫持,代理所有數(shù)據(jù)的 getter 和 setter 屬性,在每次觸發(fā) setter 的時(shí)候,都會(huì)通過(guò) Dep 來(lái)通知 Watcher,Watcher 作為Observer數(shù)據(jù)監(jiān)聽(tīng)器與Compile模板解析器之間的橋梁,當(dāng) Observer 監(jiān)聽(tīng)到數(shù)據(jù)發(fā)生改變的時(shí)候,通過(guò) Updater 來(lái)通知 Compile 更新視圖,而 Compile 通過(guò) Watcher 訂閱對(duì)應(yīng)數(shù)據(jù),綁定更新函數(shù),通過(guò) Dep 來(lái)添加訂閱者,達(dá)到雙向綁定。

121.Proxy與Object.defineProperty的優(yōu)劣對(duì)比?

Proxy的優(yōu)勢(shì)如下

  • Proxy可以直接監(jiān)聽(tīng)整個(gè)對(duì)象而非屬性。

  • Proxy可以直接監(jiān)聽(tīng)數(shù)組的變化。

  • Proxy有13中攔截方法,如ownKeys、deleteProperty、has 等是 Object.defineProperty 不具備的。

  • Proxy返回的是一個(gè)新對(duì)象,我們可以只操作新的對(duì)象達(dá)到目的,而Object.defineProperty只能遍歷對(duì)象屬性直接修改;

  • Proxy做為新標(biāo)準(zhǔn)將受到瀏覽器產(chǎn)商重點(diǎn)持續(xù)的性能優(yōu)化,也就是傳說(shuō)中的新標(biāo)準(zhǔn)的性能紅利。

Object.defineProperty 的優(yōu)勢(shì)如下

  • 兼容性好,支持 IE9,而 Proxy 的存在瀏覽器兼容性問(wèn)題,而且無(wú)法用 polyfill 磨平。

Object.defineProperty 不足在于

  • Object.defineProperty 只能劫持對(duì)象的屬性,因此我們需要對(duì)每個(gè)對(duì)象的每個(gè)屬性進(jìn)行遍歷。

  • Object.defineProperty不能監(jiān)聽(tīng)數(shù)組。是通過(guò)重寫數(shù)據(jù)的那7個(gè)可以改變數(shù)據(jù)的方法來(lái)對(duì)數(shù)組進(jìn)行監(jiān)聽(tīng)的。

  • Object.defineProperty 也不能對(duì) es6 新產(chǎn)生的 Map,Set 這些數(shù)據(jù)結(jié)構(gòu)做出監(jiān)聽(tīng)。

  • Object.defineProperty也不能監(jiān)聽(tīng)新增和刪除操作,通過(guò) Vue.set()Vue.delete來(lái)實(shí)現(xiàn)響應(yīng)式的。

122.你是如何理解Vue的響應(yīng)式系統(tǒng)的?

就是能夠自動(dòng)追蹤數(shù)據(jù)的變化,而不必手動(dòng)觸發(fā)視圖更新。Vue2.X通過(guò)Object.defineProperty()做數(shù)據(jù)劫持,而Vue3通過(guò)Proxy做數(shù)據(jù)代理,從而捕捉到對(duì)數(shù)據(jù)的get和set。

  • 什么叫數(shù)據(jù)響應(yīng)式?

簡(jiǎn)單說(shuō)就是用戶更改數(shù)據(jù)(Data)時(shí),視圖可以自動(dòng)刷新,頁(yè)面UI能夠響應(yīng)數(shù)據(jù)變化。

  • 為什么要了解Vue數(shù)據(jù)響應(yīng)式?

因?yàn)檫@是Vue的立身之本呀,連尤雨溪都在給放文檔上這樣說(shuō),“Vue 最獨(dú)特的特性之一,是其非侵入性的響應(yīng)式系統(tǒng)?!?/p>

Vue就是通過(guò)getter 和setter來(lái)對(duì)數(shù)據(jù)進(jìn)行操作,通過(guò)get()和set()函數(shù)可以生成一個(gè)虛擬屬性,來(lái)直接調(diào)用函數(shù)操作數(shù)據(jù)。這一步是被封裝起來(lái)的,我們是看不到的。

?此外,還需要一個(gè)重要的媒介API,那就是Object.defineProperty,因?yàn)閷?duì)象被定義完成后,想要更改或添加屬性(像是get和set這樣的屬性),只能通過(guò)這個(gè)Object.defineProperty來(lái)添加。接著需要實(shí)現(xiàn)對(duì)數(shù)據(jù)屬性的讀寫進(jìn)行監(jiān)控。能夠監(jiān)控就意味著能讓vm(一般生成的實(shí)例)能夠知道數(shù)據(jù)有變化,從而觸發(fā)render(data)函數(shù),頁(yè)面UI就會(huì)做出響應(yīng)。

123.既然Vue通過(guò)數(shù)據(jù)劫持可以精準(zhǔn)探測(cè)數(shù)據(jù)變化,為什么還需要虛擬DOM進(jìn)行diff檢測(cè)差異?

1.減少對(duì)真實(shí)DOM的操作

Diff 算法探討的就是虛擬 DOM 樹發(fā)生變化后,生成 DOM 樹更新補(bǔ)丁的方式。對(duì)比新舊兩株虛擬 DOM 樹的變更差異,將更新補(bǔ)丁作用于真實(shí) DOM,以最小成本完成視圖更新。

具體流程:

  1. 真實(shí) DOM 與虛擬 DOM 之間存在一個(gè)映射關(guān)系。這個(gè)映射關(guān)系依靠初始化時(shí)的 JSX 建立完成;

  2. 當(dāng)虛擬 DOM 發(fā)生變化后,就會(huì)根據(jù)差距計(jì)算生成 patch,這個(gè) patch 是一個(gè)結(jié)構(gòu)化的數(shù)據(jù),內(nèi)容包含了增加、更新、移除等;

  3. 最后再根據(jù) patch 去更新真實(shí)的 DOM,反饋到用戶的界面上。

這樣一個(gè)生成補(bǔ)丁、更新差異的過(guò)程統(tǒng)稱為 diff 算法。

這里涉及3個(gè)要點(diǎn):

  1. 更新時(shí)機(jī):更新發(fā)生在setState、Hooks 調(diào)用等操作以后

  2. 遍歷算法:采用深度優(yōu)先遍歷,從根節(jié)點(diǎn)出發(fā),沿著左子樹方向進(jìn)行縱向遍歷,直到找到葉子節(jié)點(diǎn)為止。然后回溯到前一個(gè)節(jié)點(diǎn),進(jìn)行右子樹節(jié)點(diǎn)的遍歷,直到遍歷完所有可達(dá)節(jié)點(diǎn)

  3. 優(yōu)化策略:樹、組件及元素三個(gè)層面進(jìn)行復(fù)雜度的優(yōu)化


    1. 元素比對(duì)主要發(fā)生在同層級(jí)中,通過(guò)標(biāo)記節(jié)點(diǎn)操作生成補(bǔ)丁。節(jié)點(diǎn)操作包含了插入、移動(dòng)、刪除等。其中節(jié)點(diǎn)重新排序同時(shí)涉及插入、移動(dòng)、刪除三個(gè)操作,所以效率消耗最大,此時(shí)策略三起到了至關(guān)重要的作用。通過(guò)標(biāo)記 key 的方式,React 可以直接移動(dòng) DOM 節(jié)點(diǎn),降低內(nèi)耗

    2. 在組件比對(duì)的過(guò)程中:如果組件是同一類型則進(jìn)行樹比對(duì);如果不是則直接放入補(bǔ)丁中。只要父組件類型不同,就會(huì)被重新渲染。這也就是為什么shouldComponentUpdate、PureComponent 及 React.memo 可以提高性能的原因

    3. 這一策略需要進(jìn)行樹比對(duì),即對(duì)樹進(jìn)行分層比較。樹比對(duì)的處理手法是非?!氨┝Α钡?,即兩棵樹只對(duì)同一層次的節(jié)點(diǎn)進(jìn)行比較,如果發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在了,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉,不會(huì)用于進(jìn)一步的比較,這就提升了比對(duì)效率

    4. 忽略節(jié)點(diǎn)跨層級(jí)操作場(chǎng)景,提升比對(duì)效率。


    5. 如果組件的 class 一致,則默認(rèn)為相似的樹結(jié)構(gòu),否則默認(rèn)為不同的樹結(jié)構(gòu)


    6. 同一層級(jí)的子節(jié)點(diǎn),可以通過(guò)標(biāo)記 key 的方式進(jìn)行列表對(duì)比


通過(guò)diff算法能準(zhǔn)確的獲取到具體的節(jié)點(diǎn) 進(jìn)行針對(duì)操作?。?!

124.Vue為什么沒(méi)有類似于React中shouldComponentUpdate的生命周期?

因?yàn)?Vue 的響應(yīng)式系統(tǒng)已經(jīng)在初次渲染時(shí)收集了渲染依賴的數(shù)據(jù)項(xiàng),通過(guò)自動(dòng)的方式就能夠得到相當(dāng)不錯(cuò)的性能。不過(guò),在一些場(chǎng)景下,手動(dòng)控制刷新檢查還是能夠進(jìn)一步提升渲染性能的

vue 的機(jī)制,其實(shí)就是個(gè)依賴關(guān)系管理機(jī)制。不管是計(jì)算屬性,watcher,以及 renderer,站在外部看,模型都是一樣的,即初始化的時(shí)候通過(guò)一些方法分析出來(lái)這個(gè)模塊依賴誰(shuí),等被依賴的數(shù)據(jù)更新了,這些模塊就重新運(yùn)算一遍產(chǎn)出物(實(shí)際上不盡然,比如計(jì)算屬性有惰性機(jī)制)。

具體到 renderer,哪些數(shù)據(jù)的變更會(huì)引起 dom 變更,在模板編譯的時(shí)候已經(jīng)確定了,并且寫死在生成的代碼里了。

而 react 是沒(méi)有這種自動(dòng)機(jī)制的,它去執(zhí)行 render 唯一的原因就是你主動(dòng)讓他 render。那你什么時(shí)候讓它 render 呢?工程上一般是使用一個(gè)數(shù)據(jù)流工具,數(shù)據(jù)有變化的時(shí)候發(fā)出一個(gè)事件,一股腦把數(shù)據(jù)推過(guò)來(lái),不區(qū)分哪個(gè)字段有變更(你區(qū)分了也沒(méi)用,renderer 根本不認(rèn))。如果這個(gè)數(shù)據(jù)流模型是多個(gè)組件共用的,那必然是在 render 之前有個(gè) hook 給我們個(gè)機(jī)會(huì)告訴組件“這次沒(méi)你的事兒”,有利于性能優(yōu)化。

那么,我們有沒(méi)有可能不增加代碼靜態(tài)分析環(huán)節(jié),搞清楚 react renderer 到底依賴哪些數(shù)據(jù),繼而把這個(gè)判斷自動(dòng)做掉呢?依我看不太可能,因?yàn)槲覀儾荒鼙WC運(yùn)行期跑一遍 render,它就會(huì)一次性訪問(wèn)它所有可能訪問(wèn)的數(shù)據(jù)。

125.Vue中的key到底有什么用?

1、key的作用主要是為了搞笑的更新虛擬dom,其原理是vue在patch過(guò)程中通過(guò)key可以精準(zhǔn)判斷兩個(gè)節(jié)點(diǎn)是否是同一個(gè),從而避免頻繁更新不同元素,使得整個(gè)patch過(guò)程更加高效,減少dom操作量,提高性能。2、另外,若不設(shè)置key還可能在列表更新時(shí)候引發(fā)一些隱藏的bug。3、vue中在使用相同標(biāo)簽名元素的過(guò)渡切換時(shí),也會(huì)使用到key屬性,其目的也是為了讓vue可以區(qū)分它們,否則vue只會(huì)替換其內(nèi)部屬性而不會(huì)觸發(fā)過(guò)渡效果。

126.不能用index做key

看了上面的介紹其實(shí)也很容易明白為什么不能用index作為key。

1、影響性能:當(dāng)用index作為key的時(shí)候,刪除節(jié)點(diǎn)后面的所有節(jié)點(diǎn)都會(huì)導(dǎo)致重新渲染,因?yàn)閕ndex變化了,可以也就變化了

有人說(shuō),當(dāng)你的列表數(shù)據(jù)沒(méi)有變化的時(shí)候可以用index作為key。也就是說(shuō)列表不會(huì)觸發(fā)更新元素,只有靜態(tài)展示。這種說(shuō)法你怎么看呢?之所以說(shuō)到這個(gè)問(wèn)題,是在vue官方群里面一群人應(yīng)為這個(gè)問(wèn)題討論半天。我弱弱回復(fù)一句,任何情況下都不要用index作為key。結(jié)果遭到炮轟,哎?。ǔ乔岸藢懰赖膌ist,且無(wú)操作不會(huì)引起key變化,只要是后端數(shù)據(jù),前端怎么能保證數(shù)據(jù)不變呢)。關(guān)于這個(gè)問(wèn)題,我有這樣三點(diǎn)想法:

1、代碼的規(guī)范性2、類比typescript,為什么變量要加類型,除了規(guī)范,也方便定位錯(cuò)誤3、列表的順序穩(wěn)定其實(shí)是難以保證的

127.vue項(xiàng)目中用jsx語(yǔ)法

JSX就是Javascript和XML結(jié)合的一種格式。React發(fā)明了JSX,利用HTML語(yǔ)法來(lái)創(chuàng)建虛擬DOM。當(dāng)遇到<,JSX就當(dāng)HTML解析,遇到{就當(dāng)JavaScript解析.

我為什么要在vue中用JSX?

是使用的的模板語(yǔ)法,Vue的模板實(shí)際上就是編譯成了 render 函數(shù),同樣支持 JSX 語(yǔ)法。在 Vue 官網(wǎng)中,提供 createElement 函數(shù)中使用模板中的功能。


但是極少數(shù)的 VUE項(xiàng)目用JSX語(yǔ)法 JSX語(yǔ)法 根植在react上面 ?在vue上還是 ?template舒服!



【直接收藏】前端 VUE 高階面試題(三)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
城口县| 霍林郭勒市| 汉川市| 平泉县| 正阳县| 昌都县| 潜江市| 九龙城区| 绍兴市| 古交市| 托里县| 聂拉木县| 固镇县| 屏边| 大同县| 红河县| 濮阳县| 迁西县| 宝兴县| 阜南县| 沙田区| 固始县| 海晏县| 永康市| 文水县| 大渡口区| 永安市| 隆德县| 凤台县| 定西市| 宁海县| 璧山县| 社旗县| 马龙县| 黔西| 浙江省| 商水县| 长春市| 日照市| 云梦县| 拜泉县|