前端經典面試題(60道前端面試題包含JS、CSS、React、程式題等)上

文章轉載:樂位元組

簡答題

1、什麼是防抖和節流?有什麼區別?如何實現?

參考答案

防抖

觸發高頻事件後n秒內函式只會執行一次,如果n秒內高頻事件再次被觸發,則重新計算時間

思路:

每次觸發事件時都取消之前的延時呼叫方法

function debounce(fn) {

let timeout = null; // 建立一個標記用來存放定時器的返回值

return function () {

clearTimeout(timeout); // 每當使用者輸入的時候把前一個 setTimeout clear 掉

timeout = setTimeout(() => { // 然後又建立一個新的 setTimeout, 這樣就能保證輸入字元後的 interval 間隔內如果還有字元輸入的話,就不會執行 fn 函式

fn。apply(this, arguments);

}, 500);

};

}

function sayHi() {

console。log(‘防抖成功’);

}

var inp = document。getElementById(‘inp’);

inp。addEventListener(‘input’, debounce(sayHi)); // 防抖

節流

高頻事件觸發,但在n秒內只會執行一次,所以節流會稀釋函式的執行頻率

思路:

每次觸發事件時都判斷當前是否有等待執行的延時函式

function throttle(fn) {

let canRun = true; // 透過閉包儲存一個標記

return function () {

if (!canRun) return; // 在函式開頭判斷標記是否為true,不為true則return

canRun = false; // 立即設定為false

setTimeout(() => { // 將外部傳入的函式的執行放在setTimeout中

fn。apply(this, arguments);

// 最後在setTimeout執行完畢後再把標記設定為true(關鍵)表示可以執行下一次迴圈了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉

canRun = true;

}, 500);

};

}

function sayHi(e) {

console。log(e。target。innerWidth, e。target。innerHeight);

}

window。addEventListener(‘resize’, throttle(sayHi));

2、 get請求傳參長度的誤區、get和post請求在快取方面的區別

誤區:我們經常說get請求引數的大小存在限制,而post請求的引數大小是無限制的。

參考答案

實際上HTTP 協議從未規定 GET/POST 的請求長度限制是多少。對get請求引數的限制是來源與瀏覽器或web伺服器,瀏覽器或web伺服器限制了url的長度。為了明確這個概念,我們必須再次強調下面幾點:

HTTP 協議 未規定 GET 和POST的長度限制

GET的最大長度顯示是因為 瀏覽器和 web伺服器限制了 URI的長度

不同的瀏覽器和WEB伺服器,限制的最大長度不一樣

要支援IE,則最大長度為2083byte,若只支援Chrome,則最大長度 8182byte

補充補充一個get和post在快取方面的區別:

get請求類似於查詢的過程,使用者獲取資料,可以不用每次都與資料庫連線,所以可以使用快取。

post不同,post做的一般是修改和刪除的工作,所以必須與資料庫互動,所以不能使用快取。因此get請求適合於請求快取。

3、模組化發展歷程

可從IIFE、AMD、CMD、CommonJS、UMD、webpack(require。ensure)、ES Module、

使用 visibility替換 display: none,因為前者只會引起重繪,後者會引發迴流(改變了佈局)

把 DOM 離線後修改,比如:先把 DOM 給 display:none(有一次 Reflow),然後你修改100次,然後再把它顯示出來

不要把 DOM 結點的屬性值放在一個迴圈裡當成迴圈裡的變數

for(let i = 0; i < 1000; i++) {

// 獲取 offsetTop 會導致迴流,因為需要去獲取正確的值

console。log(document。querySelector(‘。test’)。style。offsetTop)

}

不要使用 table 佈局,可能很小的一個小改動會造成整個 table 的重新佈局

動畫實現的速度的選擇,動畫速度越快,迴流次數越多,也可以選擇使用 requestAnimationFrame

CSS 選擇符從右往左匹配查詢,避免 DOM 深度過深

將頻繁執行的動畫變為圖層,圖層能夠阻止該節點回流影響別的元素。比如對於 video標籤,瀏覽器會自動將該節點變為圖層。

react、Vue

1、寫 React / Vue 專案時為什麼要在列表元件中寫 key,其作用是什麼?

參考答案

vue和react都是採用diff演算法來對比新舊虛擬節點,從而更新節點。在vue的diff函式中(建議先了解一下diff演算法過程)。在交叉對比中,當新節點跟舊節點頭尾交叉對比沒有結果時,會根據新節點的key去對比舊節點陣列中的key,從而找到相應舊節點(這裡對應的是一個key => index 的map對映)。如果沒找到就認為是一個新增節點。而如果沒有key,那麼就會採用遍歷查詢的方式去找到對應的舊節點。一種一個map對映,另一種是遍歷查詢。相比而言。map對映的速度更快。vue部分原始碼如下:

// vue專案 src/core/vdom/patch。js -488行

// 以下是為了閱讀性進行格式化後的程式碼

// oldCh 是一箇舊虛擬節點陣列

if (isUndef(oldKeyToIdx)) {

oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)

}

if(isDef(newStartVnode。key)) {

// map 方式獲取

idxInOld = oldKeyToIdx[newStartVnode。key]

} else {

// 遍歷方式獲取

idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)

}

建立map函式

function createKeyToOldIdx (children, beginIdx, endIdx) {

let i, key

const map = {}

for (i = beginIdx; i <= endIdx; ++i) {

key = children[i]。key

if (isDef(key)) map[key] = i

}

return map

}

遍歷尋找

// sameVnode 是對比新舊節點是否相同的函式

function findIdxInOld (node, oldCh, start, end) {

for (let i = start; i < end; i++) {

const c = oldCh[i]

if (isDef(c) && sameVnode(node, c)) return i

}

}

2、React 中 setState 什麼時候是同步的,什麼時候是非同步的?

參考答案

在React中,如果是由React引發的事件處理(比如透過onClick引發的事件處理),呼叫setState不會同步更新this。state,除此之外的setState呼叫會同步執行this。state。所謂“除此之外”,指的是繞過React透過addEventListener直接新增的事件處理函式,還有透過setTimeout/setInterval產生的非同步呼叫。

**原因:**在React的setState函式實現中,會根據一個變數isBatchingUpdates判斷是直接更新this。state還是放到佇列中回頭再說,而isBatchingUpdates預設是false,也就表示setState會同步更新this。state,但是,有一個函式batchedUpdates,這個函式會把isBatchingUpdates修改為true,而當React在呼叫事件處理函式之前就會呼叫這個batchedUpdates,造成的後果,就是由React控制的事件處理過程setState不會同步更新this。state。

3、下面輸出什麼

class Example extends React。Component {

constructor() {

super();

this。state = {

val: 0

};

}

componentDidMount() {

this。setState({val: this。state。val + 1});

console。log(this。state。val); // 第 1 次 log

this。setState({val: this。state。val + 1});

console。log(this。state。val); // 第 2 次 log

setTimeout(() => {

this。setState({val: this。state。val + 1});

console。log(this。state。val); // 第 3 次 log

this。setState({val: this。state。val + 1});

console。log(this。state。val); // 第 4 次 log

}, 0);

}

render() {

return null;

}

};

1、第一次和第二次都是在 react 自身生命週期內,觸發時 isBatchingUpdates 為 true,所以並不會直接執行更新 state,而是加入了 dirtyComponents,所以列印時獲取的都是更新前的狀態 0。

2、兩次 setState 時,獲取到 this。state。val 都是 0,所以執行時都是將 0 設定成 1,在 react 內部會被合併掉,只執行一次。設定完成後 state。val 值為 1。

3、setTimeout 中的程式碼,觸發時 isBatchingUpdates 為 false,所以能夠直接進行更新,所以連著輸出 2,3。

輸出: 0 0 2 3

4、為什麼虛擬dom會提高效能?

參考答案

虛擬dom相當於在js和真實dom中間加了一個快取,利用dom diff演算法避免了沒有必要的dom操作,從而提高效能。

具體實現步驟如下:

用 JavaScript 物件結構表示 DOM 樹的結構;然後用這個樹構建一個真正的 DOM 樹,插到文件當中

當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異

把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,檢視就更新了。

css

1、分析比較 opacity: 0、visibility: hidden、display: none 優劣和適用場景

參考答案

結構:display:none: 會讓元素完全從渲染樹中消失,渲染的時候不佔據任何空間, 不能點選, visibility: hidden:不會讓元素從渲染樹消失,渲染元素繼續佔據空間,只是內容不可見,不能點選 opacity: 0: 不會讓元素從渲染樹消失,渲染元素繼續佔據空間,只是內容不可見,可以點選

繼承:display: none:是非繼承屬性,子孫節點消失由於元素從渲染樹消失造成,透過修改子孫節點屬性無法顯示。visibility: hidden:是繼承屬性,子孫節點消失由於繼承了hidden,透過設定visibility: visible;可以讓子孫節點顯式。

效能:displaynone : 修改元素會造成文件迴流,讀屏器不會讀取display: none元素內容,效能消耗較大 visibility:hidden: 修改元素只會造成本元素的重繪,效能消耗較少讀屏器讀取visibility: hidden元素內容 opacity: 0 :修改元素會造成重繪,效能消耗較少

聯絡:它們都能讓元素不可見

2、清除浮動的方式有哪些?比較好的是哪一種?

參考答案

常用的一般為三種。clearfix, clear:both,overflow:hidden;

比較好是 。clearfix,偽元素萬金油版本,後兩者有侷限性。

。clearfix:after {

visibility: hidden;

display: block;

font-size: 0;

content: “ ”;

clear: both;

height: 0;

}

<!——

為毛沒有 zoom ,_height 這些,IE6,7這類需要 csshack 不再我們考慮之內了

。clearfix 還有另外一種寫法,

——>

。clearfix:before, 。clearfix:after {

content:“”;

display:table;

}

。clearfix:after{

clear:both;

overflow:hidden;

}

。clearfix{

zoom:1;

}

<!——

用display:table 是為了避免外邊距margin重疊導致的margin塌陷,

內部元素預設會成為 table-cell 單元格的形式

——>

clear:both:若是用在同一個容器內相鄰元素上,那是賊好的,有時候在容器外就有些問題了, 比如相鄰容器的包裹層元素塌陷

overflow:hidden:這種若是用在同個容器內,可以形成 BFC避免浮動造成的元素塌陷

4、css sprite 是什麼,有什麼優缺點

參考答案

概念:將多個小圖片拼接到一個圖片中。透過 background-position 和元素尺寸調節需要顯示的背景圖案。

優點:

減少 HTTP 請求數,極大地提高頁面載入速度

增加圖片資訊重複度,提高壓縮比,減少圖片大小

更換風格方便,只需在一張或幾張圖片上修改顏色或樣式即可實現

缺點:

圖片合併麻煩

維護麻煩,修改一個圖片可能需要重新佈局整個圖片,樣式

5、link與@import的區別

參考答案

link是 HTML 方式, @import是 CSS 方式

link最大限度支援並行下載,@import過多巢狀導致序列下載,出現FOUC

link可以透過rel=“alternate stylesheet”指定候選樣式

瀏覽器對link支援早於@import,可以使用@import對老瀏覽器隱藏樣式

@import必須在樣式規則之前,可以在 css 檔案中引用其他檔案

總體來說:link 優於@import

6、display: block;和display: inline;的區別

參考答案

block元素特點:

1。處於常規流中時,如果width沒有設定,會自動填充滿父容器 2。可以應用margin/padding 3。在沒有設定高度的情況下會擴充套件高度以包含常規流中的子元素 4。處於常規流中時佈局時在前後元素位置之間(獨佔一個水平空間) 5。忽略vertical-align

inline元素特點

1。水平方向上根據direction依次佈局

2。不會在元素前後進行換行

3。受white-space控制

4。margin/padding在豎直方向上無效,水平方向上有效

5。width/height屬性對非替換行內元素無效,寬度由元素內容決定

6。非替換行內元素的行框高由line-height確定,替換行內元素的行框高由height,margin,padding,border決定 7。浮動或絕對定位時會轉換為block8。vertical-align屬性生效

7、容器包含若干浮動元素時如何清理浮動

參考答案

容器元素閉合標籤前新增額外元素並設定clear: both

父元素觸發塊級格式化上下文(見塊級視覺化上下文部分)

設定容器元素偽元素進行清理推薦的清理浮動方法

/**

* 在標準瀏覽器下使用

* 1 content內容為空格用於修復opera下文件中出現

* contenteditable屬性時在清理浮動元素上下的空白

* 2 使用display使用table而不是block:可以防止容器和

* 子元素top-margin摺疊,這樣能使清理效果與BFC,IE6/7

* zoom: 1;一致

**/

。clearfix:before,

。clearfix:after {

content: “ ”; /* 1 */

display: table; /* 2 */

}

。clearfix:after {

clear: both;

}

/**

* IE 6/7下使用

* 透過觸發hasLayout實現包含浮動

**/

。clearfix {

*zoom: 1;

}

8、PNG,GIF,JPG 的區別及如何選

參考答案

GIF:

8 位畫素,256 色

無失真壓縮

支援簡單動畫

支援 boolean 透明

適合簡單動畫

JPEG:

顏色限於 256

有失真壓縮

可控制壓縮質量

不支援透明

適合照片

PNG:

有 PNG8 和 truecolor PNG

PNG8 類似 GIF 顏色上限為 256,檔案小,支援 alpha 透明度,無動畫

適合圖示、背景、按鈕

9、display,float,position 的關係

參考答案

如果display為 none,那麼 position 和 float 都不起作用,這種情況下元素不產生框

否則,如果 position 值為 absolute 或者 fixed,框就是絕對定位的,float 的計算值為 none,display 根據下面的表格進行調整。

否則,如果 float 不是 none,框是浮動的,display 根據下表進行調整

否則,如果元素是根元素,display 根據下表進行調整

其他情況下 display 的值為指定值 總結起來:絕對定位、浮動、根元素都需要調整display

10、如何水平居中一個元素

參考答案

如果需要居中的元素為常規流中 inline 元素,為父元素設定text-align: center;即可實現

如果需要居中的元素為常規流中 block 元素,1)為元素設定寬度,2)設定左右 margin 為 auto。3)IE6 下需在父元素上設定text-align: center;,再給子元素恢復需要的值

aaaaaa aaaaaa a a a a a a a a

如果需要居中的元素為浮動元素,1)為元素設定寬度,2)position: relative;,3)浮動方向偏移量(left 或者 right)設定為 50%,4)浮動方向上的 margin 設定為元素寬度一半乘以-1

aaaaaa aaaaaa a a a a a a a a

如果需要居中的元素為絕對定位元素,1)為元素設定寬度,2)偏移量設定為 50%,3)偏移方向外邊距設定為元素寬度一半乘以-1

aaaaaa aaaaaa a a a a a a a a

如果需要居中的元素為絕對定位元素,1)為元素設定寬度,2)設定左右偏移量都為 0,3)設定左右外邊距都為 auto

aaaaaa aaaaaa a a a a a a a a

JavaScript

1、JS有幾種資料型別,其中基本資料型別有哪些?

參考答案

七種資料型別

Boolean

Null

Undefined

Number

String

Symbol (ECMAScript 6 新定義)

Object

(ES6之前)其中5種為基本型別:string,number,boolean,null,undefined,

ES6出來的Symbol也是原始資料型別 ,表示獨一無二的值

Object為引用型別(範圍挺大),也包括陣列、函式,

2、Promise 建構函式是同步執行還是非同步執行,那麼 then 方法呢?

參考答案

const promise = new Promise((resolve, reject) => {

console。log(1)

resolve()

console。log(2)

})

promise。then(() => {

console。log(3)

})

console。log(4)

輸出結果是:

1

2

4

3

promise建構函式是同步執行的,then方法是非同步執行的

Promise new的時候會立即執行裡面的程式碼 then是微任務 會在本次任務執行完的時候執行 setTimeout是宏任務 會在下次任務執行的時候執行

文章轉載:樂位元組