1. 程式人生 > 實用技巧 >33道面向初中級前端的基礎面試題(持續更新中)

33道面向初中級前端的基礎面試題(持續更新中)

如需獲取完整版229頁PDF面試題,請直接滑到文末。

1.如何確定this指向

如果要判斷一個執行中函式的 this 繫結,就需要找到這個函式的直接呼叫位置。找到之後就可以順序應用下面這四條規則來判斷 this 的繫結物件。

  1. 由 new 呼叫?繫結到新建立的物件。
  2. 由 call 或者 apply (或者 bind )呼叫?繫結到指定的物件。
  3. 由上下文物件呼叫?繫結到那個上下文物件。
  4. 預設:在嚴格模式下繫結到 undefined ,否則繫結到全域性物件。

一定要注意,有些呼叫可能在無意中使用預設繫結規則。如果想“更安全”地忽略 this 繫結,你可以使用一個 DMZ 物件,比如 ø = Object.create(null) ,以保護全域性物件。
ES6 中的箭頭函式並不會使用四條標準的繫結規則,而是根據當前的詞法作用域來決定this ,具體來說,箭頭函式會繼承外層函式呼叫的 this 繫結(無論 this 繫結到什麼)。這其實和 ES6 之前程式碼中的 self = this 機制一樣

參考資料:

2.==和===的區別是什麼

==是抽象相等運算子,而===是嚴格相等運算子。==運算子是在進行必要的型別轉換後,再比較。===運算子不會進行型別轉換,所以如果兩個值不是相同的型別,會直接返回false。使用==時,可能發生一些特別的事情,例如:

1 == '1'; // true
1 == [1]; // true
1 == true; // true
0 == ''; // true
0 == '0'; // true
0 == false; // true

如果你對=====的概念不是特別瞭解,建議大多數情況下使用===

3.箭頭函式和普通函式有什麼區別

  • 函式體內的this
    物件,就是定義時所在的物件,而不是使用時所在的物件,用callapplybind也不能改變this指向
  • 不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。
  • 不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用rest引數代替。
  • 不可以使用yield命令,因此箭頭函式不能用作Generator函式。
  • 箭頭函式沒有原型物件prototype

4.白屏時間

白屏時間是指瀏覽器從輸入網址,到瀏覽器開始顯示內容的時間。

Performance 介面可以獲取到當前頁面中與效能相關的資訊,該型別的物件可以通過呼叫只讀屬性Window.performance來獲得。

performance.timing.navigationStart是一個返回代表一個時刻的 unsigned long long 型只讀屬性,為緊接著在相同的瀏覽環境下解除安裝前一個文件結束之時的 Unix 毫秒時間戳。如果沒有上一個文件,則它的值相當於 PerformanceTiming.fetchStart。

所以將以下指令碼放在</head>前面就能獲取白屏時間。

<script>
    new Date() - performance.timing.navigationStart
</script>

參考資料:

5.當你在瀏覽器輸入一個地址後發生了什麼

當···時發生了什麼?

6.頁面大量圖片,如何優化載入,優化使用者體驗

  1. 圖片懶載入。在頁面的未可視區域新增一個滾動事件,判斷圖片位置與瀏覽器頂端的距離與頁面的距離,如果前者小於後者,優先載入。
  2. 如果為幻燈片、相簿等,可以使用圖片預載入技術,將當前展示圖片的前一張和後一張優先下載。
  3. 如果圖片為css圖片,可以使用CSSsprite,SVGsprite等技術。
  4. 如果圖片過大,可以使用特殊編碼的圖片,載入時會先載入一張壓縮的特別厲害的縮圖,以提高使用者體驗。
  5. 如果圖片展示區域小於圖片的真實大小,應在伺服器端根據業務需要先進行圖片壓縮,圖片壓縮後大小與展示一致。

7.js網路請求效能優化之防抖與節流

防抖(debounce)

在函式需要頻繁觸發時,只有當有足夠空閒的時間時,才執行一次。就好像在百度搜索時,每次輸入之後都有聯想詞彈出,這個控制聯想詞的方法就不可能是輸入框內容一改變就觸發的,他一定是當你結束輸入一段時間之後才會觸發。

節流(thorttle)

預定一個函式只有在大於等於執行週期時才執行,週期內呼叫不執行。就好像你在淘寶搶購某一件限量熱賣商品時,你不斷點重新整理點購買,可是總有一段時間你點上是沒有效果,這裡就用到了節流,就是怕點的太快導致系統出現bug。

區別

在發生持續觸發事件時,防抖設定事件延遲並在空閒時間去觸發事件,而節流則是隔一定的時間觸發一次。

一個簡單的防抖示例

let timer
input.on('input', () => {
    clearTimeout(timer)
    // 停止輸入 500 毫秒後開始搜尋
    timer = setTimeout(() => {
    // 搜尋
    }, 500)
})

一個簡單的節流示例

let isClick = false
button.on('click', () => {
    if (isClick) return
    isClick = true
    // 其他程式碼。。。
    // 每 10 秒只允許點選一次
    setTimeout(() => {
    isClick = false
    }, 10000)
})

參考資料:

8.如何做到修改url引數頁面不重新整理

HTML5引入了history.pushState()history.replaceState()方法,它們分別可以新增和修改歷史記錄條目。

let stateObj = {
    foo: "bar",
};

history.pushState(stateObj, "page 2", "bar.html");
複製程式碼

假設當前頁面為foo.html,執行上述程式碼後會變為bar.html,點選瀏覽器後退,會變為foo.html,但瀏覽器並不會重新整理。pushState()需要三個引數: 一個狀態物件, 一個標題 (目前被忽略), 和 (可選的) 一個 URL. 讓我們來解釋下這三個引數詳細內容:

  • 狀態物件 — 狀態物件state是一個 JavaScript 物件,通過pushState ()建立新的歷史記錄條目。無論什麼時候使用者導航到新的狀態,popstate事件就會被觸發,且該事件的state屬性包含該歷史記錄條目狀態物件的副本。

狀態物件可以是能被序列化的任何東西。原因在於 Firefox 將狀態物件儲存在使用者的磁碟上,以便在使用者重啟瀏覽器時使用,我們規定了狀態物件在序列化表示後有640k的大小限制。如果你給pushState()方法傳了一個序列化後大於 640k 的狀態物件,該方法會丟擲異常。如果你需要更大的空間,建議使用sessionStorage以及localStorage.

  • 標題 — Firefox 目前忽略這個引數,但未來可能會用到。傳遞一個空字串在這裡是安全的,而在將來這是不安全的。二選一的話,你可以為跳轉的state傳遞一個短標題。

  • URL — 該引數定義了新的歷史URL記錄。注意,呼叫pushState()後瀏覽器並不會立即載入這個 URL,但可能會在稍後某些情況下載入這個 URL,比如在使用者重新開啟瀏覽器時。新URL不必須為絕對路徑。如果新URL是相對路徑,那麼它將被作為相對於當前 URL 處理。新 URL 必須與當前URL同源,否則pushState()會丟擲一個異常。該引數是可選的,預設為當前 URL。

參考資料:

9.請用js去除字串空格

去除所有空格

str.replace(/\s/g, '')

去除兩邊空格

str.replace(/^\s+|\s+$/g, '')
// 原生方法
str.trim()

10.建立物件有幾種方法

  • 字面量
const obj = {a: 1}
  • 建構函式
function Obj(val) {
    this.a = val
}

const obj = new Obj(1)
  • Object.create
const obj = Object.create({a: 1})

11.null和undefined的區別

null表示一個物件是“沒有值”的值,也就是值為“空”

undefined表示一個變數聲明瞭沒有初始化(賦值)

undefinednull在if語句中,都會被自動轉為false

undefined不是一個有效的JSON,而null

undefined的型別(typeof)是undefined

null的型別(typeof)是object

Javascript將未賦值的變數預設值設為undefined

Javascript從來不會將變數設為null。 它是用來讓程式設計師表明某個用var宣告的變數時沒有值的

12.非同步求和

要求

假設有一臺本地機器,無法做加減乘除運算,因此無法執行 a + b、a+ = 1 這樣的 JS 程式碼,然後我們提供一個伺服器端的 HTTP API,可以傳兩個數字型別的引數,響應結果是這兩個引數的和,這個 HTTP API 的 JS SDK(在本地機器上執行)的使用方法如下:

asyncAdd(3, 5, (err, result) => {
  console.log(result); // 8
});

模擬實現:

function asyncAdd(a, b, cb) {
  setTimeout(() => {
    cb(null, a + b);
  }, Math.floor(Math.random()*100))
}

現在要求在本地機器上實現一個 sum 函式,支援以下用法:

(async () => {
  const result1 = await sum(1, 4, 6, 9, 1, 4);
  const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);
  const result3 = await sum(1, 6, 0, 5);
  console.log([result1, result2, result3]); // [25, 36, 12]
})();

要求 sum 能在最短的時間裡返回以上結果

實現

function asyncAdd(a, b, cb) {
    setTimeout(() => {
        cb(null, a + b);
    }, Math.floor(Math.random()*100))
}

function sum(...args) {
    const result = []
    function _sum(resolve, reject) {
        new Promise((r, j) => {
            let a = args.pop()
            let b = args.pop()
            a = a !== undefined? a : 0
            b = b !== undefined? b : 0 // 如果訪問的元素超出了陣列範圍,則轉為 0
            asyncAdd(a, b, (err, res) => {
                if (err) j(err)
                r(res)
            })

            if (args.length) {
                _sum(resolve, reject)
            }
        })
        .then(val => {
            result.push(val)
            setTimeout(() => {
                if (args.length <= 0) {
                    resolve(sum(...result))
                }
            }, 100)
        })
    }

    return new Promise((resolve, reject) => {
        if (!args || !args.length) resolve(0)
        if (args.length == 1) resolve(args[0])
        _sum(resolve, reject)
    })
}

(async () => {
    const result1 = await sum(1, 4, 6, 9, 1, 4)
    const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7)
    const result3 = await sum(1, 6, 0, 5)
    console.log([result1, result2, result3]) // [25, 36, 12]
})()

13.CommonJS,ES module 是什麼,有什麼區別?

它們都是一種模組規範,例如 Node 使用的就是 CommonJS 規範。ES module 則是語言標準上的模組規範。

區別:

  1. CommonJS 模組使用require()module.exports,ES6 模組使用importexport
  2. CommonJS 模組輸出的是一個值的淺拷貝,ES6 模組輸出的是值的引用。
  3. CommonJS 模組是執行時載入,ES6 模組是編譯時輸出介面。
  4. CommonJS 模組的require()是同步載入模組,ES6 模組的import命令是非同步載入,有一個獨立的模組依賴的解析階段。
  5. ES6 模組之中,頂層的 this 指向 undefined;CommonJS 模組的頂層 this 指向當前模組,
  6. 對於迴圈載入的處理方法不同

第 3 個差異是因為 CommonJS 載入的是一個物件(即module.exports屬性),該物件只有在指令碼執行完才會生成。

而 ES6 模組不是物件,它的對外介面只是一種靜態定義,在程式碼靜態解析階段就會生成。

參考資料:

14.preload和prefetch

preload

preload<link>標籤rel屬性的屬性值,同時需要配合as屬性使用。

as指定將要預載入的內容的型別,使得瀏覽器能夠:

  1. 更精確地優化資源載入優先順序。
  2. 匹配未來的載入需求,在適當的情況下,重複利用同一資源。
  3. 為資源應用正確的內容安全策略。
  4. 為資源設定正確的 Accept 請求頭。

看一下這個示例:

<link rel="preload" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" as="script">

這種做法將把<link>標籤塞入一個預載入器中。

這個預載入器在不阻塞頁面 onload 事件的情況下,去載入資源。

我們可以通過以下兩個示例來作一個對比:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        console.time('load')
    </script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/2.1.10/chart/bar.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<script>
window.onload = () => {
    console.timeEnd('load') // load: 1449.759033203125ms
}
</script>
</body>
</html>

上面這個示例從載入到觸發 onload 事件需要大概 1400 ms 的時間。再看一下使用 preload 預載入的時間:

<link rel="preload" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" as="script">
<link rel="preload" href="https://cdn.bootcdn.net/ajax/libs/echarts/2.1.10/chart/bar.js" as="script">
<link rel="preload" href="https://unpkg.com/element-ui/lib/index.js" as="script">
<link rel="preload" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" as="style">

window.onload = () => {
    console.timeEnd('load') // load: 10.8818359375ms
}

用 preload 來載入資源,只需要 10 ms 就觸發了 onload 事件。

說明同樣是下載檔案,使用 preload 不會阻塞 onload 事件。

prefetch

prefetchpreload不同,使用prefetch屬性指定的資源將在瀏覽器空閒時間下下載。

在資源的請求頭如果發現有下面這個屬性,就代表它是通過prefetch載入的:

purpose: prefetch

另外,空閒時間是如何確定、如何獲取的,目前還沒有相關 API。

15.preload 和 defer 的區別

preload 和 defer 的相同點是非同步下載。那它們的不同點是什麼呢?

preload 下載的資源只有在遇到同樣的 script 標籤時,才會執行對應的指令碼。例如下面預載入的vue.js

<link rel="preload" as="script" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">

只有在遇到下面的標籤時,才會執行載入的vue.js

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

defer 則是非同步下載資源,在所有元素解析完成後,觸發 DOMContentLoaded 事件前執行。

16.window.onload 和 DOMContentLoaded 的區別

當整個頁面及所有依賴資源如樣式表和圖片都已完成載入時,將觸發load事件。

它與 DOMContentLoaded不同,當純HTML被完全載入以及解析時,DOMContentLoaded 事件會被觸發,而不必等待樣式表,圖片或者子框架完成載入。

17.Object 與 Map 的區別

  1. Object 只能選擇字元、數值、符號作為 key,Map 則可以使用任何型別的資料作為 key。
  2. Map 例項會維護鍵值對的插入順序,因此可以根據插入順序執行迭代操作。Chrome Opera 中使用 for-in 語句遍歷 Object 屬性時會遵循一個規律:它們會先提取所有 key 的 parseFloat 值為非負整數的屬性,然後根據數字順序對屬性排序首先遍歷出來,然後按照物件定義的順序遍歷餘下的所有屬性。其它瀏覽器則完全按照物件定義的順序遍歷屬性。

選擇 Object 還是 Map

對於多數Web開發任務來說,選擇 Object 還是 Map 只是個人偏好問題,影響不大。不過,對於在乎記憶體和效能的開發者來說,物件和對映之間確實存在顯著的差別。

1. 記憶體佔用

Object 和 Map 的工程級實現在不同瀏覽器間存在明顯差異,但儲存單個鍵/值對所佔用的記憶體數量都會隨鍵的數量線性增加。批量新增或刪除鍵/值對則取決於各瀏覽器對該型別記憶體分配的工程實現。

不同瀏覽器的情況不同,但給定固定大小的記憶體, Map 大約可以比 Object 多儲存50%的鍵/值對。

2. 插入效能

向 Object 和 Map 中插入新鍵/值對的消耗大致相當,不過插入Map 在所有瀏覽器中一般會稍微快一點兒。對這兩個型別來說,插入速度並不會隨著鍵/值對數量而線性增加。

如果程式碼涉及大量插入操作,那麼顯然 Map 的效能更佳。

3. 查詢速度

與插入不同,從大型 Object 和 Map 中查詢鍵/值對的效能差異極小,但如果只包含少量鍵/值對,則 Object 有時候速度更快。在把 Object 當成陣列使用的情況下(比如使用連續整數作為屬性),瀏覽器引擎可以進行優化,在記憶體中使用更高效的佈局。

這對 Map 來說是不可能的。對這兩個型別而言,查詢速度不會隨著鍵/值對數量增加而線性增加。如果程式碼涉及大量查詢操作,那麼某些情況下可能選擇 Object 更好一些。

4. 刪除效能

使用 delete 刪除 Object 屬性的效能一直以來飽受詬病,目前在很多瀏覽器中仍然如此。為此,出現了一些偽刪除物件屬性的操作,包括把屬性值設定為 undefined 或 null 。但很多時候,這都是一 種討厭的或不適宜的折中。

而對大多數瀏覽器引擎來說, Map 的 delete() 操作都比插入和查詢更快。如果程式碼涉及大量刪除操作,那麼毫無疑問應該選擇 Map 。

參考資料:

18.為什麼 WeakMap 和 WeakSet 的鍵只能使用物件?

是為了保證只有通過鍵物件的引用來取得值。

const m = new WeakMap()
m.set({}, 100) // 由於 {} 沒有在其他地方引用,所以在垃圾回收時,這個值也會被回收。

const a = {}
m.set(a, 100) // 如果使用這種方式,則不會被回收。因為 {} 有 a 變數在引用它。

a = null // 將 a 置為空後,m 裡的值 100 在垃圾回收時將會被回收。

如果允許原始值,那就沒辦法區分初始化時使用的字串字面量和初始化之後使用的一個相等的字串了。

所以這句話的意思很明確:

const a = {} // 在建立物件時,分配了一塊記憶體,並把這塊記憶體的地址傳給 a 
m.set(a, 100) // 執行 set 操作時,實際上是將 a 指向的記憶體地址和 100 關聯起來

const a = 'abc' // 由於基本資料型別在傳遞時,傳遞的是值,而不是引用。
m.set(a, 100) // 所以執行 set 操作時,實際上是將新的 'abc' 和 100 關聯起來,而不是原來 a 變數指向的那個。
          // 那這樣就會有問題,m 裡儲存的永遠是沒有被引用的鍵,隨時都會被回收。

參考資料:

HTML

19.HTML5語義化

什麼是語義化?就是用合理、正確的標籤來展示內容,比如h1~h6定義標題。

好處

  • 易於使用者閱讀,樣式丟失的時候能讓頁面呈現清晰的結構。
  • 有利於SEO,搜尋引擎根據標籤來確定上下文和各個關鍵字的權重。
  • 方便其他裝置解析,如盲人閱讀器根據語義渲染網頁
  • 有利於開發和維護,語義化更具可讀性,程式碼更好維護,與CSS3關係更和諧。

20.為什麼最好把 CSS 的<link>標籤放在<head></head>之間?為什麼最好把 JS 的<script>標籤恰好放在</body>之前,有例外情況嗎?

<link>放在<head>

這種做法可以讓頁面逐步呈現,提高了使用者體驗。將樣式表放在文件底部附近,會使許多瀏覽器(包括 Internet Explorer)不能逐步呈現頁面。一些瀏覽器會阻止渲染,以避免在頁面樣式發生變化時,重新繪製頁面中的元素。這種做法可以防止呈現給使用者空白的頁面或沒有樣式的內容。

<script>標籤恰好放在</body>之前

指令碼在下載和執行期間會阻止 HTML 解析。把<script>標籤放在底部,保證 HTML 首先完成解析,將頁面儘早呈現給使用者。

如果一定要放在<head>中,可以讓<script>標籤使用defer屬性。

21.什麼是漸進式渲染(progressive rendering)?

漸進式渲染是用於提高網頁效能(尤其是提高使用者感知的載入速度),以儘快呈現頁面的技術。

在以前網際網路頻寬較小的時期,這種技術更為普遍。如今,移動終端的盛行,而行動網路往往不穩定,漸進式渲染在現代前端開發中仍然有用武之地。

一些舉例:

  • 圖片懶載入——頁面上的圖片不會一次性全部載入。當用戶滾動頁面到圖片部分時,JavaScript 將載入並顯示影象。
  • 確定顯示內容的優先順序(分層次渲染)——為了儘快將頁面呈現給使用者,頁面只包含基本的最少量的 CSS、指令碼和內容,然後可以使用延遲載入指令碼或監聽DOMContentLoaded/load事件載入其他資源和內容。
  • 非同步載入 HTML 片段——當頁面通過後臺渲染時,把 HTML 拆分,通過非同步請求,分塊傳送給瀏覽器。更多相關細節可以在這裡找到。

22.. viewport

Viewport :字面意思為檢視視窗,在移動web開發中使用。表示將裝置瀏覽器寬度虛擬成一個特定的值(或計算得出),這樣利於移動web站點跨裝置顯示效果基本一致。移動版的 Safari 瀏覽器最新引進了 viewport 這個 meta tag,讓網頁開發者來控制 viewport 的大小和縮放,其他手機瀏覽器也基本支援。

在移動端瀏覽器當中,存在著兩種視口,一種是可見視口(也就是我們說的裝置大小),另一種是視窗視口(網頁的寬度是多少)。 舉個例子:如果我們的螢幕是320畫素 * 480畫素的大小(iPhone4),假設在瀏覽器中,320畫素的螢幕寬度能夠展示980畫素寬度的內容。那麼320畫素的寬度就是可見視口的寬度,而能夠顯示的980畫素的寬度就是視窗視口的寬度。

為了顯示更多的內容,大多數的瀏覽器會把自己的視窗視口擴大,簡易的理解,就是讓原本320畫素的螢幕寬度能夠容下980畫素甚至更寬的內容(將網頁等比例縮小)。

Viewport屬性值

  • width 設定layout viewport 的寬度,為一個正整數,或字串"width-device"
  • initial-scale 設定頁面的初始縮放值,為一個數字,可以帶小數
  • minimum-scale 允許使用者的最小縮放值,為一個數字,可以帶小數
  • maximum-scale 允許使用者的最大縮放值,為一個數字,可以帶小數
  • height 設定layout viewport 的高度,這個屬性對我們並不重要,很少使用
  • user-scalable 是否允許使用者進行縮放,值為"no"或"yes", no 代表不允許,yes代表允許這些屬性可以同時使用,也可以單獨使用或混合使用,多個屬性同時使用時用逗號隔開就行了。

23.Reflow和Repaint

Reflow

當涉及到DOM節點的佈局屬性發生變化時,就會重新計算該屬性,瀏覽器會重新描繪相應的元素,此過程叫Reflow(迴流或重排)。

Repaint

當影響DOM元素可見性的屬性發生變化 (如 color) 時, 瀏覽器會重新描繪相應的元素, 此過程稱為Repaint(重繪)。因此重排必然會引起重繪。

引起Repaint和Reflow的一些操作

  • 調整視窗大小
  • 字型大小
  • 樣式表變動
  • 元素內容變化,尤其是輸入控制元件
  • CSS偽類啟用,在使用者互動過程中發生
  • DOM操作,DOM元素增刪、修改
  • width, clientWidth, scrollTop等佈局寬高的計算

Repaint和Reflow是不可避免的,只能說對效能的影響減到最小,給出下面幾條建議:

  • 避免逐條更改樣式。建議集中修改樣式,例如操作className。
  • 避免頻繁操作DOM。建立一個documentFragment或div,在它上面應用所有DOM操作,最後新增到文件裡。設定display:none的元素上操作,最後顯示出來。
  • 避免頻繁讀取元素幾何屬性(例如scrollTop)。絕對定位具有複雜動畫的元素。
  • 絕對定位使它脫離文件流,避免引起父元素及後續元素大量的迴流

參考資料:

24. img中的alt和元素的title屬性作用

  • img的alt屬性

如果無法顯示影象,瀏覽器將顯示alt指定的內容

  • 元素title屬性

在滑鼠移到元素上時顯示title的內容

25.href和src區別

href

href標識超文字引用,用在link和a等元素上,href是引用和頁面關聯,是在當前元素和引用資源之間建立聯絡
若在文件中新增href ,瀏覽器會識別該文件為 CSS 檔案,就會並行下載資源並且不會停止對當前文件的處理。這也是為什麼建議使用 link 方式載入 CSS,而不是使用 @import 方式。

src

src表示引用資源,替換當前元素,用在img,script,iframe上,src是頁面內容不可缺少的一部分。
當瀏覽器解析到src ,會暫停其他資源的下載和處理(圖片不會暫停其他資源下載和處理),直到將該資源載入、編譯、執行完畢,圖片和框架等也如此,類似於將所指向資源應用到當前內容。這也是為什麼建議把 js 指令碼放在底部而不是頭部的原因。

參考資料:

25.瀏覽器的渲染過程

  1. 解析HTML生成DOM樹。
  2. 解析CSS生成CSSOM規則樹。
  3. 將DOM樹與CSSOM規則樹合併在一起生成渲染樹。
  4. 遍歷渲染樹開始佈局,計算每個節點的位置大小資訊。
  5. 呼叫 GPU 繪製,合成圖層。
  6. 將渲染樹每個節點繪製到螢幕。

26.為何會出現瀏覽器相容問題

  • 同一產品,版本越老 bug 越多
  • 同一產品,版本越新,功能越多
  • 不同產品,不同標準,不同實現方式

處理相容問題的思路

  1. 要不要做
  • 產品的角度(產品的受眾、受眾的瀏覽器比例、效果優先還是基本功能優先)
  • 成本的角度 (有無必要做某件事)

2.做到什麼程度

  • 讓哪些瀏覽器支援哪些效果

3..如何做

  • 根據相容需求選擇技術框架/庫(jquery)

  • 根據相容需求選擇相容工具(html5shiv.js、respond.js、css reset、normalize.css、Modernizr)

  • 條件註釋、CSS Hack、js 能力檢測做一些修補

  • 漸進增強(progressive enhancement): 針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高階瀏覽器進行效果、互動等改進和追加功能達到更好的使用者體驗

  • 優雅降級 (graceful degradation): 一開始就構建完整的功能,然後再針對低版本瀏覽器進行相容。

參考資料:

27.doctype有什麼用

doctype是一種標準通用標記語言的文件型別宣告,目的是告訴標準通用標記語言解析器要使用什麼樣的文件型別定義(DTD)來解析文件。

宣告是用來指示web瀏覽器關於頁面使用哪個HTML版本進行編寫的指令。 宣告必須是HTML文件的第一行,位於html標籤之前。

瀏覽器本身分為兩種模式,一種是標準模式,一種是怪異模式。

瀏覽器通過doctype來區分這兩種模式,doctype在html中的作用就是觸發瀏覽器的標準模式,如果html中省略了doctype,瀏覽器就會進入到Quirks模式的怪異狀態。

在這種模式下,有些樣式會和標準模式存在差異。

而html標準和dom標準值規定了標準模式下的行為,沒有對怪異模式做出規定,因此不同瀏覽器在怪異模式下的處理也是不同的,所以一定要在html開頭使用doctype。

28.行內元素和塊級元素有哪些

行內元素

一個行內元素只佔據它對應標籤的邊框所包含的空間
一般情況下,行內元素只能包含資料和其他行內元素

b, big, i, small, tt
abbr, acronym, cite, code, dfn, em, kbd, strong, samp, var
a, bdo, br, img, map, object, q, script, span, sub, sup
button, input, label, select, textarea

塊級元素

佔據一整行,高度、行高、內邊距和外邊距都可以改變,可以容納塊級標籤和其他行內標籤

header,form,ul,ol,table,article,div,hr,aside,figure,canvas,video,audio,footer

29.行內元素、塊級元素區別

行內元素:和其他元素都在一行上,高度、行高及外邊距和內邊距都不可改變(邊距上下方向不可改變,左右方向可以改變),文字圖片的寬度不可改變,只能容納文字或者其他行內元素;其中img是行元素

塊級元素:總是在新行上開始,高度、行高及外邊距和內邊距都可控制,可以容納內斂元素和其他元素;行元素轉換為塊級元素方式:display:block;

30. iframe框架有那些優缺點

優點:

  • iframe能夠原封不動的把嵌入的網頁展現出來。
  • 如果有多個網頁引用iframe,那麼你只需要修改iframe的內容,就可以實現呼叫的每一個頁面內容的更改,方便快捷。
  • 網頁如果為了統一風格,頭部和版本都是一樣的,就可以寫成一個頁面,用iframe來巢狀,可以增加程式碼的可重用。
  • 如果遇到載入緩慢的第三方內容如圖示和廣告,這些問題可以由iframe來解決。

缺點:

  • 搜尋引擎的爬蟲程式無法解讀這種頁面
  • 框架結構中出現各種滾動條
  • 使用框架結構時,保證設定正確的導航連結。
  • iframe頁面會增加伺服器的http請求

31. label標籤有什麼作用

label標籤通常是寫在表單內,它關聯一個控制元件,使用label可以實現點選文字選取對應的控制元件。

<input type="checkbox" id="test">
<label for="test" >test</label>

32.HTML5的form如何關閉自動完成功能

將不想要自動完成的forminput設定為autocomplete=off

33. DOM和BOM有什麼區別

DOM

Document Object Model,文件物件模型

DOM 是為了操作文件出現的 API,document 是其的一個物件

DOM和文件有關,這裡的文件指的是網頁,也就是html文件。DOM和瀏覽器無關,他關注的是網頁本身的內容。

BOM

Browser Object Model,瀏覽器物件模型

BOM 是為了操作瀏覽器出現的 API,window 是其的一個物件

我平時一直有整理面試題的習慣,有隨時跳出舒適圈的準備,不知不覺整理了229頁了,在這裡分享給大家,有需要的點選這裡免費領取題目+解析PDF

篇幅有限,僅展示部分內容

如果你需要這份完整版的面試題+解析,【點選我】就可以了。

希望大家明年的金三銀四面試順利,拿下自己心儀的offer!