2023-08-25 前端面試

前端面試分享

一、 實(shí)現(xiàn)垂直居中的幾種方式

Flexbox布局:
使用Flexbox是實(shí)現(xiàn)垂直居中最簡(jiǎn)單和常用的方法之一。將容器設(shè)置為display: flex;,然后使用align-items: center;將項(xiàng)目在交叉軸上居中。

.container {
 display: flex;
 align-items: center; /* 垂直居中 */
}

絕對(duì)定位和負(fù)邊距:
這種方法適用于已知高度的情況。將要垂直居中的元素設(shè)置為position: absolute;,然后使用top: 50%;將其移動(dòng)到父容器的中間,再通過負(fù)邊距將其向上移動(dòng)自身高度的一半。

Copy code
.centered {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

表格布局:
使用display: table;和display: table-cell;可以實(shí)現(xiàn)垂直居中,類似于表格的布局。

.table-container {
  display: table;
  height: 100%; /* 父容器要有確定的高度 */
}

.table-cell {
  display: table-cell;
  vertical-align: middle; /* 垂直居中 */
}

Grid布局:
類似于Flexbox,使用Grid布局也可以實(shí)現(xiàn)垂直居中。

Copy code
.container {
  display: grid;
  place-items: center; /* 垂直居中 */
}

使用line-height:
這適用于只有單行文本的情況。將line-height設(shè)置為和容器高度相等,使文本在容器中垂直居中。

Copy code
.container {
  height: 100px; /* 容器高度 */
  line-height: 100px; /* 垂直居中 */
}

二、什么是重排,重繪

重排(Reflow)和重繪(Repaint)是與瀏覽器渲染流程相關(guān)的兩個(gè)概念,它們?cè)谇岸诵阅軆?yōu)化中非常重要。

重排(Reflow):
重排指的是當(dāng)DOM的變化影響了元素的幾何屬性(例如位置、尺寸)時(shí),瀏覽器需要重新計(jì)算元素的幾何屬性,并重新布局頁面。重排是一項(xiàng)昂貴的操作,因?yàn)樗婕暗秸麄€(gè)文檔的重新布局和元素的重新計(jì)算。

重排可能發(fā)生在以下情況:

添加、刪除、更新DOM元素。
修改元素的樣式,如修改寬度、高度、字體大小等。
瀏覽器窗口尺寸變化。
重繪(Repaint):
重繪指的是當(dāng)元素的外觀發(fā)生變化,但不影響布局時(shí),瀏覽器會(huì)將新的樣式繪制到屏幕上。重繪的開銷相對(duì)較小,因?yàn)樗恍枰匦掠?jì)算元素的幾何屬性。

重繪可能發(fā)生在以下情況:

修改元素的顏色、背景色、文本顏色等。
添加陰影、邊框等。
因此,為了提高前端性能,應(yīng)該盡量減少重排和重繪的次數(shù)。減少重排和重繪可以通過以下方式來實(shí)現(xiàn):

使用CSS動(dòng)畫:使用transform和opacity等屬性進(jìn)行動(dòng)畫,它們不會(huì)引起重排。
批量修改樣式:避免多次單獨(dú)修改樣式,可以將多個(gè)修改合并到一次操作中。
使用離線DOM操作:在修改DOM之前,將元素脫離文檔流(例如使用display: none;),完成修改后再放回文檔流,這樣可以避免多次重排。
使用虛擬DOM:在框架(如React、Vue)中,使用虛擬DOM來最小化重排和重繪的次數(shù)。
理解重排和重繪的原理以及如何避免不必要的操作可以幫助你優(yōu)化前端性能,提升用戶體驗(yàn)。

三、說一下原型和原型鏈

在JavaScript中,原型(Prototype)和原型鏈(Prototype Chain)是理解對(duì)象和繼承的核心概念
1. 原型(Prototype):
在JavaScript中,每個(gè)對(duì)象都有一個(gè)原型。原型是一個(gè)對(duì)象,包含可共享的屬性和方法。當(dāng)你訪問一個(gè)對(duì)象的屬性或方法時(shí),如果對(duì)象本身沒有該屬性或方法,JavaScript引擎會(huì)在原型鏈上查找

2.原型鏈(Prototype Chain):
原型鏈?zhǔn)且环N機(jī)制,它定義了對(duì)象之間的繼承關(guān)系。每個(gè)對(duì)象都有一個(gè)指向其原型的鏈接,從而構(gòu)成了一個(gè)鏈條。當(dāng)你訪問一個(gè)對(duì)象的屬性或方法時(shí),如果對(duì)象本身沒有,JavaScript會(huì)在原型鏈上一層一層地查找,直到找到對(duì)應(yīng)的屬性或方法,或者到達(dá)原型鏈的末尾(null)。

原型和原型鏈?zhǔn)荍avaScript中實(shí)現(xiàn)繼承和對(duì)象共享屬性方法的基礎(chǔ)。理解它們有助于你更好地組織代碼,實(shí)現(xiàn)代碼復(fù)用,并更深入地理解JavaScript中對(duì)象的工作原理。

四、EventLoop事件循環(huán)

事件循環(huán)(Event Loop)是一種在單線程環(huán)境下處理異步操作的機(jī)制。它在JavaScript中起著至關(guān)重要的作用,使得異步操作如定時(shí)器、網(wǎng)絡(luò)請(qǐng)求、用戶交互等能夠以非阻塞的方式執(zhí)行,從而不會(huì)阻礙代碼的執(zhí)行。

JavaScript是單線程的,這意味著它一次只能執(zhí)行一個(gè)任務(wù)。但在現(xiàn)代的應(yīng)用中,我們需要處理許多異步操作,如加載資源、處理用戶輸入等。這就是事件循環(huán)的作用,它允許JavaScript引擎在執(zhí)行同步任務(wù)的同時(shí),處理異步任務(wù)。

事件循環(huán)的工作原理如下:

1. 執(zhí)行同步任務(wù):JavaScript引擎首先執(zhí)行主線程上的同步任務(wù),即代碼按順序執(zhí)行。

2. 執(zhí)行微任務(wù):在同步任務(wù)執(zhí)行完成后,會(huì)檢查是否有微任務(wù)(Microtask)需要執(zhí)行。微任務(wù)是一個(gè)異步的任務(wù)隊(duì)列,其中的任務(wù)會(huì)在當(dāng)前任務(wù)執(zhí)行完畢后立即執(zhí)行。

3. 執(zhí)行宏任務(wù):如果在執(zhí)行微任務(wù)時(shí),產(chǎn)生了新的宏任務(wù)(Macrotask),那么會(huì)將新的宏任務(wù)推入到宏任務(wù)隊(duì)列中,等待執(zhí)行。宏任務(wù)包括定時(shí)器、I/O操作、事件監(jiān)聽等。

4. 循環(huán):不斷地重復(fù)上述過程,即執(zhí)行同步任務(wù)、微任務(wù),然后執(zhí)行一個(gè)宏任務(wù),再執(zhí)行微任務(wù),如此循環(huán)。

這個(gè)循環(huán)不斷地進(jìn)行,使得JavaScript能夠處理多個(gè)異步操作,同時(shí)保持單線程的特性。微任務(wù)通常比宏任務(wù)優(yōu)先級(jí)更高,這意味著微任務(wù)會(huì)在下一個(gè)宏任務(wù)執(zhí)行之前得到處理。

以下是事件循環(huán)的簡(jiǎn)化示意圖:

[同步任務(wù)] -> [微任務(wù)] -> [宏任務(wù)] -> [微任務(wù)] -> [宏任務(wù)] -> ...
  • 事件循環(huán)機(jī)制是理解JavaScript異步編程的關(guān)鍵概念之一。深入了解它可以幫助你更好地編寫高效、非阻塞的代碼。

五、Vue 組件之間如何傳值

1. Props(屬性傳遞):

使用Props(屬性)來從父組件向子組件傳遞數(shù)據(jù)。父組件可以在子組件上使用屬性綁定,子組件通過props屬性接收傳遞的值。

父組件:

<template>
  <child-component :message="parentMessage" />
</template>

<script>
export default {
  data() {
    return {
      parentMessage: 'Hello from parent'
    };
  }
};
</script>

子組件:

<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: ['message']
};
</script>

2. $emit(自定義事件):

使用$emit方法在子組件中觸發(fā)一個(gè)自定義事件,并將數(shù)據(jù)傳遞給父組件。

子組件:

<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
export default {
  methods: {
    sendMessage() {
      this.$emit('message', 'Hello from child');
    }
  }
};
</script>

父組件:

<template>
  <child-component @message="handleMessage" />
</template>

<script>
export default {
  methods: {
    handleMessage(message) {
      console.log(message); // 輸出 'Hello from child'
    }
  }
};
</script>

3. Vuex(狀態(tài)管理庫):

對(duì)于大型應(yīng)用程序,你可以使用Vuex來在多個(gè)組件之間共享狀態(tài)。Vuex將狀態(tài)存儲(chǔ)在中央存儲(chǔ)中,允許不同組件之間實(shí)時(shí)同步數(shù)據(jù)。

Provide/Inject:
使用provide在父組件中提供數(shù)據(jù),并使用inject在子組件中注入數(shù)據(jù)。這在跨層級(jí)組件傳遞數(shù)據(jù)時(shí)非常有用,但要注意不要過度使用,以保持組件的獨(dú)立性。

父組件:

<template>
  <child-component />
</template>

<script>
export default {
  provide: {
    message: 'Hello from parent'
  }
};
</script>

子組件:

<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  inject: ['message']
};
</script>
  • 以上是一些常見的Vue組件之間傳遞數(shù)據(jù)的方法。你可以根據(jù)應(yīng)用的需要選擇最適合的方式。

六、說一下VueX 和 pinia

Vuex 和 Pinia 都是 Vue.js 狀態(tài)管理庫,用于管理應(yīng)用程序的狀態(tài)(數(shù)據(jù))并實(shí)現(xiàn)組件之間的通信。盡管它們的目標(biāo)相同,但在實(shí)現(xiàn)方式和使用上存在一些區(qū)別。

Vuex:

官方狀態(tài)管理庫:Vuex 是 Vue.js 官方提供的狀態(tài)管理庫,被廣泛用于 Vue.js 應(yīng)用中。

中心化存儲(chǔ):Vuex 使用單一的全局狀態(tài)樹來存儲(chǔ)應(yīng)用的所有狀態(tài)。狀態(tài)存儲(chǔ)在一個(gè)對(duì)象中,組件通過 getters 和 mutations 來讀取和修改狀態(tài)。

模塊化:Vuex 允許將狀態(tài)劃分為多個(gè)模塊,每個(gè)模塊可以擁有自己的 state、getters、mutations、actions 等。

Actions 和 Mutations:在 Vuex 中,actions 用于處理異步操作,而 mutations 用于同步地修改狀態(tài)。通常,異步操作應(yīng)該在 actions 中處理,然后再調(diào)用 mutations 來修改狀態(tài)。

插件和工具支持:Vuex 支持插件和開發(fā)者工具,使你可以更好地進(jìn)行調(diào)試和監(jiān)測(cè)狀態(tài)變化。

Pinia:

去中心化存儲(chǔ):Pinia 的設(shè)計(jì)理念是去中心化存儲(chǔ),每個(gè)組件擁有自己的狀態(tài),不再需要全局的狀態(tài)樹。每個(gè)組件都有自己的 store 實(shí)例。

類型安全:Pinia 借助 TypeScript 的支持,提供了類型安全的狀態(tài)管理。它使用類型來確保在 store 中的數(shù)據(jù)和方法調(diào)用時(shí)的正確性。

Composition API 集成:Pinia 在 Vue 3 的 Composition API 上構(gòu)建,使得它與 Vue 3 中的開發(fā)方式更加契合。

輕量級(jí):Pinia 的核心庫相對(duì)較小,只包含了最基本的功能,但它支持插件擴(kuò)展來增加更多功能。

插件和工具支持:雖然 Pinia 在插件和工具方面沒有像 Vuex 那樣成熟的生態(tài),但正在逐漸發(fā)展中。

總之,Vuex 是 Vue.js 生態(tài)系統(tǒng)中的經(jīng)典狀態(tài)管理庫,適用于大多數(shù)應(yīng)用。而 Pinia 則是基于 Vue 3 Composition API 構(gòu)建的新一代狀態(tài)管理庫,強(qiáng)調(diào)去中心化存儲(chǔ)和類型安全。你可以根據(jù)你的項(xiàng)目需求和偏好來選擇適合的庫。

七、Vue 2 和 Vue 3 有什么區(qū)別

Vue 3 是 Vue.js 的下一個(gè)主要版本,帶來了許多改進(jìn)和新特性。以下是 Vue 2 和 Vue 3 之間的一些重要區(qū)別:

Composition API(組合式API):
Vue 3 引入了 Composition API,這是一個(gè)新的 API 風(fēng)格,允許開發(fā)者更靈活地組織組件的邏輯。相比 Vue 2 中的選項(xiàng)分離,Composition API 更強(qiáng)調(diào)邏輯的組合,使代碼更具可讀性和維護(hù)性。

更好的響應(yīng)性系統(tǒng):
Vue 3 的響應(yīng)性系統(tǒng)使用 Proxy 替代了 Vue 2 中的 Object.defineProperty,這帶來了更好的性能和更精確的響應(yīng)性追蹤。

更快的渲染性能:
Vue 3 使用了虛擬 DOM 的優(yōu)化算法,減少了不必要的重渲染和 DOM 操作,從而提升了渲染性能。

更小的包體積:
Vue 3 的包體積相對(duì)較小,通過 tree-shaking 和按需引入,可以進(jìn)一步減小應(yīng)用的包大小。

Teleport 和 Suspense:
Vue 3 引入了 Teleport 組件,用于在 DOM 中的任何位置渲染組件,以及 Suspense 組件,用于更好地管理異步組件和數(shù)據(jù)加載狀態(tài)。

全局 API 的變化:
Vue 3 中一些全局 API 發(fā)生了變化,比如 Vue.component 變?yōu)?app.component,Vue.directive 變?yōu)?app.directive,等等。

自定義渲染器:
Vue 3 允許開發(fā)者創(chuàng)建自定義渲染器,以便將 Vue 渲染到非 DOM 的目標(biāo),比如 Canvas、WebGL 等。

更好的 TypeScript 支持:
Vue 3 的代碼庫進(jìn)行了重構(gòu),使得 TypeScript 支持更為完善,并且提供了更好的類型推斷。

更多的優(yōu)化和改進(jìn):
Vue 3 進(jìn)行了多項(xiàng)優(yōu)化和改進(jìn),包括更好的編譯器、更豐富的錯(cuò)誤提示、更靈活的插件系統(tǒng)等。

盡管 Vue 3 帶來了許多改進(jìn),但由于 API 的變化,從 Vue 2 遷移到 Vue 3 可能需要進(jìn)行一些調(diào)整。因此,在遷移之前,建議查閱 Vue 3 的文檔和遷移指南,以便更好地理解和適應(yīng)這些變化。

八、什么情況下是 undefined 什么情況下是 null

九、項(xiàng)目中有遇到什么困難的嗎 (我回答的是 性能優(yōu)化)

性能優(yōu)化確實(shí)是前端開發(fā)中常遇到的一個(gè)重要困難之一。在大型應(yīng)用中,隨著頁面變得更加復(fù)雜,性能問題可能會(huì)變得更加明顯。以下是一些可能遇到的性能優(yōu)化困難以及如何解決它們的方法:

1. 慢加載時(shí)間:頁面加載時(shí)間過長(zhǎng)可能會(huì)導(dǎo)致用戶體驗(yàn)不佳。

解決方法:

使用懶加載:將頁面分割成多個(gè)模塊,按需加載。
壓縮資源:壓縮 JavaScript、CSS 和圖片等資源以減小文件大小。
使用 CDN:將靜態(tài)資源部署在內(nèi)容分發(fā)網(wǎng)絡(luò)上,加速加載速度。
使用瀏覽器緩存:使用緩存策略來減少不必要的網(wǎng)絡(luò)請(qǐng)求。

2. 渲染性能問題:頻繁的重渲染可能導(dǎo)致頁面響應(yīng)變慢。

解決方法:

使用虛擬 DOM:使用虛擬 DOM 減少真實(shí) DOM 操作,提升渲染性能。
避免不必要的重渲染:使用 shouldComponentUpdate 或 PureComponent 優(yōu)化組件更新。
使用 CSS 動(dòng)畫:使用 CSS 動(dòng)畫來取代 JavaScript 動(dòng)畫,提高動(dòng)畫性能。

3.內(nèi)存泄漏:長(zhǎng)時(shí)間運(yùn)行的應(yīng)用可能會(huì)出現(xiàn)內(nèi)存泄漏,導(dǎo)致性能下降。

解決方法:

定期進(jìn)行內(nèi)存分析:使用瀏覽器開發(fā)者工具或?qū)I(yè)工具來分析內(nèi)存使用情況。
清理無用數(shù)據(jù):手動(dòng)清理無用的對(duì)象、事件監(jiān)聽等,防止無法回收的內(nèi)存。

4.數(shù)據(jù)傳遞與狀態(tài)管理:在大型應(yīng)用中,數(shù)據(jù)傳遞和狀態(tài)管理可能變得復(fù)雜。

解決方法:

使用合適的狀態(tài)管理庫:如 Vuex、Redux 或 Mobx,來管理全局狀態(tài)。
使用局部狀態(tài):組件之間的狀態(tài)可以盡量保持局部,避免過度使用全局狀態(tài)。

5.異步操作:頻繁的異步操作可能導(dǎo)致性能問題和代碼難以維護(hù)。

解決方法:

使用節(jié)流和防抖:對(duì)于頻繁觸發(fā)的事件,使用節(jié)流和防抖來限制操作次數(shù)。
異步優(yōu)化:使用 Web Workers 處理耗時(shí)操作,避免阻塞主線程。

6.移動(dòng)端適配:在移動(dòng)設(shè)備上,性能問題更為突出,需要特別關(guān)注。

解決方法:

使用響應(yīng)式設(shè)計(jì):使用 CSS 媒體查詢和彈性布局來適配不同屏幕尺寸。
圖片優(yōu)化:使用適當(dāng)尺寸和格式的圖片,以減少移動(dòng)設(shè)備上的加載時(shí)間。

這些只是性能優(yōu)化中的一些常見困難和解決方法。優(yōu)化是一個(gè)持續(xù)的過程,需要不斷的監(jiān)測(cè)和改進(jìn)。通過合理的優(yōu)化策略,可以顯著提升應(yīng)用的性能和用戶體驗(yàn)。

十、箭頭函數(shù)可以是構(gòu)造函數(shù)嗎

箭頭函數(shù)在語法上是一種特殊類型的函數(shù),它具有與普通函數(shù)(也稱為常規(guī)函數(shù)或標(biāo)準(zhǔn)函數(shù))不同的行為和特性。箭頭函數(shù)不適用于所有用例,而且不能被用作構(gòu)造函數(shù)。

主要區(qū)別如下:

1. 沒有自己的this:
最大的區(qū)別是箭頭函數(shù)沒有自己的this上下文。它繼承了其所在上下文中的this。這意味著在箭頭函數(shù)內(nèi)部,無法通過this來訪問調(diào)用它的對(duì)象。而在普通函數(shù)中,this會(huì)根據(jù)調(diào)用方式動(dòng)態(tài)變化。

2. 不能用作構(gòu)造函數(shù):
由于箭頭函數(shù)沒有自己的this,也沒有prototype屬性,它們不能被用作構(gòu)造函數(shù)來創(chuàng)建對(duì)象。普通函數(shù)可以通過new關(guān)鍵字創(chuàng)建實(shí)例,但箭頭函數(shù)不能。

3. 沒有arguments對(duì)象:
箭頭函數(shù)也沒有自己的arguments對(duì)象。如果你需要使用函數(shù)參數(shù),應(yīng)該使用剩余參數(shù)語法(...args)。

因此,由于箭頭函數(shù)的特殊行為,它們不適合作為構(gòu)造函數(shù)。如果你需要在函數(shù)內(nèi)部使用this,并且希望能夠通過new關(guān)鍵字創(chuàng)建對(duì)象,應(yīng)該使用普通函數(shù)。

// 普通函數(shù),可以用作構(gòu)造函數(shù)
function RegularFunction() {
  this.property = 'Value';
}
// 箭頭函數(shù),不能用作構(gòu)造函數(shù)
const ArrowFunction = () => {
  // 無法使用this
};

const instance1 = new RegularFunction(); // 正常
const instance2 = new ArrowFunction(); // 報(bào)錯(cuò):ArrowFunction is not a constructor

總之,箭頭函數(shù)主要用于簡(jiǎn)化函數(shù)表達(dá)式,以及在需要較短的函數(shù)體時(shí)使用。如果你需要在函數(shù)內(nèi)部使用this,或者希望將函數(shù)用作構(gòu)造函數(shù)創(chuàng)建對(duì)象,應(yīng)該使用普通函數(shù)。

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

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

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