【面經系列】一線互聯網大廠前端面試技巧深入淺出總結

来源:https://www.cnblogs.com/fecommunity/archive/2019/11/22/11908984.html
-Advertisement-
Play Games

揭秘一線互聯網大廠前端面試技巧,系統全面總結了前端面試中涉及的CSS和JS、性能優化、錯誤監控等高頻考點,並深入講解了面試過程中的註意事項和提分點。 ...


一二面(基礎面)

1. 一面基礎面

1.1 面試準備

1.1.1 個人簡歷

  • 基本信息:姓名-年齡-手機-郵箱-籍貫
  • 工作經歷:時間-公司-崗位-職責-技術棧-業績(哪些成就)
  • 學歷: 博士 > 碩士 > 本科 > 大專
  • 工作經歷:時間-公司-崗位-職責-技術棧-業績
  • 開源項目:GitHub和說明

1.2.2 自我陳述

1.2.2.1 把我面試的溝通方向(別把自己帶到坑裡面)

答:我平時喜歡研究一些網站,並對一些技術的原理和好玩的點感興趣,我自己也喜歡思考,也喜歡嘗試探索有沒有更好的方式和實現。(有所收留,不要全部說出來,稍微留一點懸念留作面試官來提問)

1.2.2.2 豁達、自信的適度發揮

答:適當自信,向自己擅長的方向上面來引路;要讓面試官來欣賞我,而不是來鄙視他。

1.2.2.3 自如談興趣

(豁達自信,適當收住),巧妙演示實例,適時討論疑問(不知道的問題請求指導一下,如何去解決,不要說不知道,或者不瞭解)

1.2.2.4 節奏要適宜

切忌小聰明(儘量把問題的所有實現方法都寫出來,表現出來的是熟練)

1.2 面試實戰

[!NOTE]
> 1. 方向要對,過程要細(性能優化,過程詳細)
> 2. 膽子要大、心態要和(演算法題認真思考,認真使勁想;敢於承擔責任,不要輕易放棄)

2. CSS相關

2.1 頁面佈局

2.1.1 如何實現垂直居中佈局呢?

1.已知寬高

/*v1*/
.container {
    position: absolute;
    left: 50%;
    top: 50%;
    marigin-left: -width / 2;
    marigin-top: -width / 2;
}

/*v2*/
.container {
    position: absolute;
    top: calc(50% - 5em);
    left: calc(50% - 9em);
}

2.未知寬高

/*v1*/
.container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/*v2:flex+ auto*/
.wrapper {
    dislay: flex;
}
.content {
    margin: auto;
}

/*v3. 父元素居中*/
.wrapper {
    display: flex;
    /* 盒子橫軸的對齊方式 */
    justify-content: center;
    /* 盒子縱軸的對齊方式 */
    align-items: center;
}

/*v4.body內部居中*/
.content {
     /* 1vh = 1% * 視口高度 */
      margin: 50vh auto;
      transform: translateY(-50%);
}

2.1.2 如何實現水平居中佈局呢?

  1. 如果需要居中的元素為常規流中 inline / inline-block 元素,為父元素設置 text-align: center;
  2. 父元素上設置 text-align: center; 居中元素上margin 為 auto。
  3. 如果元素positon: absolute; 那麼
    • 0)設置父元素postion: relative
    • 1)為元素設置寬度,
    • 2)偏移量設置為 50%,
    • 3)偏移方向外邊距設置為元素寬度一半乘以-1

2.1.3 如何實現三欄佈局呢?

  1. left和right寫在center前面,並且分別左右浮動;
  2. 左右區域分別postion:absolute,固定到左右兩邊;中間的這個div因為是塊級元素,所以在水平方向上按照他的包容塊自動撐開。
  3. 父元素display: table;並且寬度為100%; 每一個子元素display: table-cell; 左右兩側添加寬度,中間不加寬度
  4. 包裹這個3個塊的父元素display: flex; 中間的元素flex: 1;
  5. 網格佈局
/* 網格佈局 */
.wrapper {
    display: grid;
    width: 100%;
    grid-template-columns: 300px 1fr 300px;
}

2.2 知道CSS動畫的實現嗎?

[!NOTE]
知道transition 過渡動畫和animation 關鍵幀動畫區別和具體實現。

  • 1.CSS動畫實現輪播圖
  • 2.CSS動畫實現旋轉的硬幣
  • 3.CSS動畫實現鐘擺效果

2.3 CSS盒子模型

2.3.1 說一下CSS的盒子模型?標準模型和IE模型的區別?CSS如何設置這兩種模型?

  • 標準盒子模型:width = content
  • IE盒子模型:width = content + pading + border

  • box-sizing : content-box
  • box-sizing : border-box

2.4 CSS樣式獲取

2.4.1 JS如何設置獲取盒子模型對應的寬度和高度?(面試重點)

  • dom.style.width/height : 只能取到內聯樣式的的屬性信息(拿不到外部引入的CSS樣式信息的)
  • dom.currentStyle.width/height : 會拿到瀏覽器渲染之後的屬性信息(IE瀏覽器)
  • window.getComputedStyle(dom).width/height : Chrome/Firefox 相容, Firefox可以通過document.defaultView.getComputedStyle(dom)的方式來獲取
  • dom.getBoundingClientRect().width/height : 可以獲取距離viewport位置的寬度和高度

2.5 BFC

2.5.1 根據盒子模型解釋邊距額重疊問題?邊距重疊問題的解決方案?

CSS盒子模型

  • 父子元素
  • 兄弟元素
  • 其他 --------------------------計算方式:以參數的最大值來進行計算

解決方案:對父級元素創建BFC

2.5.2 BFC原理

[!NOTE]
BFC: 塊級格式化上下文,IFC(內聯格式化上下文)

  1. 在BFC的垂直邊距上面會發生重疊
  2. BFC的區域不會與浮動元素的BOX重疊
  3. BFC在頁面上是一個獨立的渲染區域,外部的元素不會影響到我,同時也不會影響到外部的元素
  4. 計算BFC的高度的時候,浮動元素也會參與運算

2.5.3 如何創建BFC?

  1. float值不是none
  2. position值不是static或者relative
  3. display值為table, table-cell, inline-box1.
  4. overflow : auto/hidden

2.5.4 BFC的使用場景?(重點理解)

  1. 解決邊距的重疊問題
<section id="margin">
        <style>
            #margin {
                background-color: #4eff35;
                overflow: hidden;
            }
            #margin>p {
                /*上 左右 下*/
                margin: 5px auto 25px;
                background-color: #ff255f;
            }
        </style>
        <p>1</p>
        <!--把一個元素放在一個容器裡面,為這個容器創建BFC即可解決邊距重疊問題-->
        <div style="overflow: hidden">
            <p>2</p>
        </div>

        <p>3</p>
</section>
  1. BFC 不與float部分重疊的解決
<section id="layout">
      <style>
          #layout {
              background-color: #48adff;
          }
          #layout .left {
              float: left;
              height: 300px;
              width: 200px;
              background-color: #ff4344;
          }
          #layout .right {
              height: 400px;
              background-color: #ff255f;
              /*給右邊的這個盒子容器創建一個BFC, 這個容器裡面的內容就會沿著垂直方向延伸*/
              overflow: auto;
              /*overflow: auto;*/
              /*display: table;*/
              /*float: left;*/
              /*position: fixed;*/
          }
      </style>
      <div class="left">
          LEFT
      </div>
      <div class="right">
          RIGHT
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
          <p>111</p>
      </div>
  </section>
  1. BFC子元素即使是float元素也要參與運算
<section id="float">
      <style>
          /*一個盒子內部的內容如果是浮動的話,那麼這個盒子的內容實際上是不參與父容器高度計算的*/
          #float {
              background-color: red;
              /*overflow: hidden;*/
              float: left;
          }
          #float .float {
              float: left;
              font-size: 30px;
          }
      </style>
      <div class="float">
          我是浮動的元素
      </div>
</section>

3. 事件相關

3.1 DOM事件

3.1.1 DOM事件的級別有哪些?

[!NOTE]
DOM級別一共可以分為四個級別:DOM0級、DOM1級、DOM2級和DOM3級。而DOM事件分為3個級別:DOM0級事件處理,DOM2級事件處理和DOM3級事件處理。

  1. DOM0 : element.onclick = function(e) {}
    DOM1 :該標準中未涉及到事件綁定的相關東西
  2. DOM2 : element.addEventListener('click', function(e){}, false), 一個DOM元素可以添加多個事件
  3. DOM3 : element.addEventListener('keyup', function(e){}, false),在DOM2標準基礎上面增加了新的事件類型:滑鼠事件,鍵盤事件,焦點事件

3.1.2 DOM事件模型有哪些?

  1. 事件捕獲:從外向內, window -> document -> body -> button
  2. 事件冒泡:從內向外,button -> body -> document -> window

3.1.3 DOM事件流?

瀏覽器為當前的頁面與用戶進行交互的過程中,點擊滑鼠後事件如何傳入和響應的呢?

    1. 捕獲階段:從外部容器開始向內
    1. 目標階段:事件通過捕獲到達目標階段
    1. 冒泡階段:從目標元素再上傳到window對象

3.1.4 什麼事件可以代理?什麼事件不可以代理呢?

什麼樣的事件可以用事件委托,什麼樣的事件不可以用呢?

[!NOTE]

  1. 通常支持事件冒泡(Event Bubbling)的事件類型為滑鼠事件和鍵盤事件,例如:mouseover, mouseout, click, keydown, keypress。
  2. 介面事件(指的是那些不一定與用戶操作有關的事件)則通常不支持事件冒泡(Event Bubbling),例如:load, change, submit, focus, blur。

很明顯:focus 和 blur 都屬於不支持冒泡的介面事件。既然都不支持冒泡,那又如何實現事件代理呢?

3.1.5 IE和DOM事件流的區別?

IE採用冒泡型事件 Netscape使用捕獲型事件 DOM使用先捕獲後冒泡型事件

  1. 冒泡型事件模型: button -> div -> body (IE瀏覽器本身只支持Bubbling不支持Capturing)
  2. 捕獲型事件模型: body -> div-> button (Netscape事件流,網景瀏覽器公司)
  3. DOM事件模型: body -> div -> button -> button -> div -> body (先捕獲後冒泡,除了IE以外的其他瀏覽器都支持標準的DOM事件處理模型)

[!NOTE]

  • 規範和瀏覽器實現的差別?
    • DOM2級事件規範的捕獲階段,事件從文檔節點document開始傳播,現代瀏覽器大多數都是從window對象開始傳播事件的;
    • DOM2級事件規範捕獲階段不涉及事件目標,現代瀏覽器大多數都在這個階段包含事件目標。

3.1.6 事件對象event的屬性方法的差別?

        IE                    DOM
cancelBubble = true    stopPropagation()    // 停止冒泡
returnValue = false    preventDefault()     // 阻止元素預設事件
srcEelement            target               // 事件目標

3.1.7 描述DOM事件捕獲的具體流程?

window -> document -> HTML標簽 -> body -> ... -> 目標元素

[!NOTE]
關鍵點: 註意根節點是window這個對象的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div id="container">
      <style>
          #container {
              width: 200px;
              height: 200px;
              background-color: #ff255f;
          }
      </style>
  </div>
  <script>
      // 事件捕獲機制
      window.addEventListener('click', function(){
          console.log('window capture');
      }, true)
      document.addEventListener('click', function () {
          console.log('document capture');
      }, true)
      document.documentElement.addEventListener('click', function () {
          console.log('HTML capture');
      }, true)
      document.body.addEventListener('click', function () {
          console.log('body capture');
      }, true)
      document.getElementById('container').addEventListener('click', function () {
          console.log('container capture');
      }, true)

      // 事件冒泡機制
      window.addEventListener('click', function(){
          console.log('window capture');
      })
      document.addEventListener('click', function () {
          console.log('document capture');
      })
      document.documentElement.addEventListener('click', function () {
          console.log('HTML capture');
      })
      document.body.addEventListener('click', function () {
          console.log('body capture');
      })
      document.getElementById('container').addEventListener('click', function () {
          console.log('container capture');
      })

      // 輸出結果
      window capture  --> document capture --> HTML capture --> body capture --> container capture --> container capture -->  body capture --> HTML capture --> document capture --> window capture
  </script>
</body>
</html>

3.1.8 如何拿到HTML這個標簽節點元素呢?(加分項)

  var html = document.documentElement;

3.1.9 描述Event對象的常見應用?

  1. e.preventDefault() : 阻止預設事件(如阻止a標簽的預設跳轉行為)
  2. e.stopPropagation() : 阻止事件冒泡的行為
  3. *** e.stopImmediatePropagation() : 事件響應的優先順序的應用場景,如果一個元素綁定了多個事件,但是又不想讓其他的事件執行的時候使用該方法【也會阻止冒泡】
  4. e.currentTarget : 當前所綁定的事件對象
  document.documentElement.onclick = function(e) {
    console.log(e.currentTarget, e.target);       // <html><body>...</body></html>()給綁定事件的那個元素, 當前被點擊的那個元素
  }

[!NOTE]
e.target : 當前被點擊的元素,父元素使用事件代理的方式來實現,可以直接使用該屬性獲取被點擊的那個元素

3.2 如何自定義事件?(重點))

3.2.1 如何給一個按鈕綁定一個自己定義的事件呢?

  // v1. 使用Event對象來自定義事件
  // 開始創建一個自己定義的事件對象
  var eve = new Event('customEvent');
  // 使用dom2事件處理的方式來給這個元素綁定一個事件
  var dom = document.documentElement;
  dom.addEventListener('customEvent', function(e) {
    console.log('customEvent called!');
  });
  // 下麵的這句話可以在適合的場景中來觸發一個自己定義的事件對象
  setTimeout(function(){
    // 在1s之後觸發這個事件
    dom.dispatchEvent(eve);
  }, 1000)


  // v2. 使用CustomEvent來實現自定義事件
  var dom = document.documentElement;
  // 使用CustomEvent的方式可以在事件觸發的時候傳遞一個參數,然後通過e.detail 的方式來獲取這個參數信息
  var myClick = new CustomEvent('myClick', {detail : {name : 'zhangsan', age : 24}});
  dom.addEventListener('myClick', function(e){
    console.log(e.detail, e.target)
  })
  dom.dispatchEvent(myClick);

4. HTTP協議

4.1 HTTP協議的主要特點?

  • 簡單快速
  • 靈活
  • 無連接
  • 無狀態

4.2 HTTP報文的組成部分?

  • 請求報文
    請求行:請求方法 資源地址 HTTP版本
    請求頭: key : value
    空行 :
    請求體 : name=zhangsan&age=18
  • 響應報文 : HTTP版本 狀態碼
    狀態行
    響應頭
    空行
    響應體

4.3 HTTP方法?

  • GET : 獲取資源
  • POST : 傳輸資源
  • PUT :更新資源
  • DELETE : 刪除資源
  • HEAD :獲取報文首部
  • OPTIONS : 允許客戶端查看伺服器的性能。

4.4 POST和GET的區別?

  1. GET請求在瀏覽器回退的時候是無害的,而POST會再次提交請求
  2. GET請求產生的URL地址可以被收藏,而POST不可以
  3. GET請求會被瀏覽器主動緩存,而POST不會,除非主動設置
  4. GET請求只能進行URL編碼,而POST支持多種編碼方式
  5. GET請求參數會被完整第保留在瀏覽器的歷史記錄裡面,而POST參數不會被保留
  6. GET請求愛URL中傳送的參數的長度是有限的(2KB),而POST沒有限制
  7. 對參數的數據類型,GET值接受ASCII字元,而POST沒有限制
  8. POST比GET更安全,GET參數直接暴露在URL上,所以不能用來傳遞敏感信息
    9. GET參數通過URL傳遞,POST參數直接放在了Request body中

4.5 HTTP狀態碼?

4.5.1 狀態碼的第一位

  • 1xx :指示信息-表示請求已接收,繼續處理(重點)
  • 2xx :成功-表示請求已被成功接收
  • 3xx :重定向-要完成請求必須進行更進一步的操作
  • 4xx :客戶端錯誤-請求有語法錯誤或請求無法實現
  • 5xx :伺服器錯誤-伺服器未能實現合法的請求

4.5.2 狀態碼詳解

  • 200 OK : 客戶端請求成功
  • 206 Partial Content : 客戶端發送了一個帶有Range頭的GET請求(Video標簽或者audio標簽在請求數據的時候)
  • 301 Moved Permanently : 請求的頁面已經轉移到了新的URL
  • 302 Found : 所請求的頁面已經臨時轉移到了新的URL
  • 304 Not Modified :客戶端有緩衝的文檔併發出了一個條件下的請求,原來緩衝的文檔還可以繼續使用
  • 400 Bad Request : 客戶端請求有語法錯誤,不被伺服器所理解
  • 401 Unauthorized : 請求未經授權,這個狀態碼必須和WWW-Authenticate報頭域一起使用
  • 403 Forbidden:對被請求頁面的訪問被禁止
  • 404 Not Found : 請求資源不存在
  • 500 Internal Server Error :伺服器發生不可預期的錯誤,原來緩衝的文檔還可以繼續使用
  • 503 Service Unavailable : 請求未完成,伺服器臨時過載或宕機,一段時間後可能恢復正常

4.6 什麼是持久連接?

[!NOTE]
HTTP協議採用‘請求-應答’模式, HTTP1.1版本才支持的,使用Keep-alive欄位可以建立一個長連接,從而不需要每次請求都去建立一個新的連接。

4.7 什麼是管線化?

4.7.1 基本概念

  • 在使用持久連接(Keep-alive)的情況下,某個連接上的消息的傳遞類似於:請求1 --> 響應1 --> 請求2 --> 響應2 --> 請求3 --> 響應3
  • 管線化的過程: 請求1 --> 請求2 --> 請求3 --> 響應1 --> 響應2 --> 響應3

4.7.2 管線化的特點(特點)

  1. 管線化機制通過持久連接完成,僅在HTTP1.1版本之後支持
  2. 只有GET和HEAD請求可以進行管線化,POST有所限制的
  3. 初次創建連接的時候不應該啟動管線機制,因為對方(伺服器)不一定支持HTTP1.1版本的協議
  4. 管線化不會影響到響應到來的順序,HTTP響應返回的順序並未改變
  5. HTTP1.1 要求伺服器支持管線化,但並不要求伺服器也對響應進行管線化處理,只是要求對於管線化的請求不失敗即可
  6. 由於上面提到的伺服器端問題,開啟管線化很可能並不會帶來大幅度的性能提升,而且很多伺服器和代理程式對管線化的支持並不好,因此現代的瀏覽器如Chrome和Firefox預設並沒有開啟管線化支持

5. 原型鏈

5.1 創建對象的幾種方法?

// 1. 使用字面量的方式來創建
var o1 = {name : 'zhangsan'};
var o11 = new Object({name : 'zhangsan'});

// 2. 使用普通構造函數的方式來創建
var M = function(){
    this.name = 'zhangsan';
}
var o2 = new M();

// 3. Object.create方法
var p = {name : 'zhangsan'};
var o3 = Object.create(p);

5.2 原型、構造函數、實例、原型鏈?

構造函數:使用new運算符來聲明一個實例(任何函數都是可以通過構造函數來使用的)

原型鏈:通過原型鏈可以找到上一級別的原型對象

原型對象:多個實例公用的數據和屬性或者方法
原型對象

5.3 instanceof的原理?

[!NOTE]
instanceof 檢測一個對象A是不是另一個對象B的實例的原理是:查看對象B的prototype指向的對象是否在對象A的[[prototype]]鏈上。如果在,則返回true,如果不在則返回false。不過有一個特殊的情況,當對象B的prototype為null將會報錯(類似於空指針異常)。

// 2. 使用普通構造函數的方式來創建
var M = function(){
  this.name = 'zhangsan';
}
var o2 = new M();
undefined
o2.__proto__ == M.prototype
true
o2.__proto__ == M.prototype
true
o2.__proto__.constructor === Object
false
o2.__proto__.constructor === M
true

5.4 new運算符的原理?

  1. 一個新對象被創建。它繼承於foo.prototype
  2. 構造函數foo被執行。執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定為這個新實例,new foo等同於 new foo(),只能用在不傳遞任何參數的情況
  3. 如果構造函數返回了一個“對象”,那麼這個對象會取代整個new出來的結果。如果構造函數沒有返回對象,那麼new 出來的結果為步驟1創建的對象
// new 一個對象的過程
var _new = function (fn) {
  // 1. 創建一個對象,這個對象要繼承fn這個構造函數的原型對象
  var o = Object.create(fn.prototype);
  // 2. 執行構造函數
  var k = fn.call(o, arguments);
  // 3. 看下執行的這個函數的運行效果是不是函數
  if (typeof k === 'object'){
      return k;
  }
  else
  {
      return o;
  }
}

6. 面向對象

6.1 類與繼承:如何實現繼承,繼承的幾種實現方式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script>
  // 類的聲明
  function Animal1() {
      this.name = 'name';
  }
  // ES6 中的class的聲明
  class Animal2 {
      constructor(){
          this.name = 'name';
      }
  }

  console.log(new Animal1(), new Animal2());
  ///////////////////////////////////////////////////////////////////////////////////////////


  // 如何實現類的繼承呢???-----------本質:原型鏈
  // v1. 藉助構造函數實現繼承
  function Parent1() {
      this.name = 'parent1'
  }
  Parent1.prototype.sayHello = function () {
      console.log('hello');
  }
  function Child1() {
      // 執行父親的構造函數:
      // 1. 實現原理:將父級函數的this指向了這個子類的實例上面去了
      // 2. 缺點:父親的原型鏈上面的方法或者屬性不能被繼承;只能實現部分繼承
      Parent1.call(this);
      this.type = 'child1';
  }
  // 沒有參數的時候,可以直接new + 函數名稱
  console.log(res = new Child1);




  // v2. 藉助原型鏈實現繼承
  function Parent2() {
      this.name = 'parent2';
      this.data = [1, 2, 3];
  }
  Parent2.prototype.sayHello = function () {
      console.log('hello');
  }
  function Child2() {
      this.type = 'child2';
  }
  // prototype 就是為了讓這個對象的實例可以訪問到原型鏈上的內容
  Child2.prototype = new Parent2();
  // new Child2().__proto__ === Child2.prototype  // true
  // new Child2().__proto__.name                  // parent2
  // 原型鏈繼承的缺點:
  // 1. 原理:通過修改原型鏈來實現對象的繼承關係
  // 2. 缺點:修改第一個對象上面的屬性,會直接修改第二個對象屬性數據(引用類型)
  var c1 = new Child2();
  var c2 = new Child2();
  c1.data.push(100, 200, 300);

  // v3. 組合繼承
  function Parent3() {
      this.name = 'parent3';
      this.data = [1, 2, 3];
  }
  function Child3() {
      // 1. 借用構造函數繼承
      Parent3.call(this);
      this.type = 'child3';
  }
  // 2. 原型鏈繼承
  // child3的原型對象是Parent3的一個實例對象,但是這個實例對象中是沒有constructor這個屬性的,因此尋找屬性的時候回沿著這個實例對象的原型鏈繼續向上尋找new Parent3().prototype 這個原型對象的,
  // 最終在Parent3.prototype這個原型對象中找到了這個屬性,new一個對象找的實際上是{Parent3.prototype.constructor : Parent3}
  Child3.prototype = new Parent3();
  var c1 = new Child3();
  var c2 = new Child3();
  c1.data.push(100, 200, 300);
  // 組合繼承的特點:
  // 1. 原理:結合借用構造函數繼承和原型鏈繼承的優點,摒棄二者的缺點
  // 2. 缺點:父類構造函數在創建實例的時候總共執行了兩次(new Parent3(), new Child3())


  // v4. 組合繼承的優化1
  function Parent4() {
      this.name = 'parent4';
      this.data = [1, 2, 3];
  }
  function Child4() {
      // 1. 借用構造函數繼承
      Parent4.call(this);
      this.type = 'child4';
  }
  // 讓子類的構造函數的原型對象和父類構造函數的原型對象執向同一個對象(都是同一個對象)
  Child4.prototype = Parent4.prototype;
  // 測試
  var c1 = new Child4();
  var c2 = new Child4();
  console.log(c1 instanceof Child4, c1 instanceof Parent4);
  console.log(c1.constructor)         // Parent4? 如何實現:c1.constructor(c1.__proto__.constructor) === Child4 呢?
  // 缺點:
  // 1. 無法通過原型對象的constructor屬性來獲取對象的屬性對應的構造函數了(子類和父類公用的是一個contructor)
  // 2. obj instanceof Child4 === true; obj instanceof Parent4 === true
  // 3. obj.__proto__.constructor === Child4; obj.__proto__.constructor === Parent4  ???

  // v5. 組合繼承的優化2【完美寫法】
  function Parent5() {
      this.name = 'parent5';
      this.data = [1, 2, 3, 4, 5];
  }
  function Child5(){
      Parent5.call(this);
      this.type = 'child5';
  }

  // 通過創建中間對象的方式來把兩個對象區分開
  // var obj = new Object(); obj.__proto__ = Constructor.prototype;
  // 1. Object.create創建的對象obj, 這個obj的原型對象就是參數
  // 2. Child5的原型對象是Child5.prototype
  // 3. Child5.prototype = obj,obj這個對象相當於就是一個中間的橋梁關係
  Child5.prototype = Object.create(Parent5.prototype);
  // 當前的方式還是會按照原型鏈一級一級向上尋找的, 給Child5的原型對象上面綁定一個自己定義的constructor屬性
  Child5.prototype.constructor = Child5;

  // var s1 = new Child5()

  // 上面的代碼等價於
  var obj = Object.create(Parent5.prototype);     // obj.prototype = Parent5.prototype
  Child5.prototype = obj;
  Child5.prototype.constructor = Child5;
  // 1. 對象之間就是通過__proto__ 屬性向上尋找的
  // 2. 尋找規則: child5 ---> Child5.prototype ---> obj(Object.create(Parent5.prototype)) ---> Parent5.prototype


  // 技巧:不要讓面試官問太多題目:拖拉時間【擠牙膏】,把一個問題儘量吃透
  // 消化這一塊內容
</script>
</body>
</html>

[!WARNING]
面試技巧

  1. 不要讓面試官問太多題目:拖拉時間【擠牙膏】,把一個問題儘量吃透
  2. 知識深度

7. 通信

7.1 什麼是同源策略個限制?

[!NOTE]
同源策略限制是從一個源載入的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。(一個源的文檔或腳本是沒有權利直接操作另外一個源的文檔或腳本的)

  1. Cookie, LocalStorage和IndexDB無法讀取
  2. DOM無法獲得;(document.body是無法獲取的)
  3. Ajax請求不能發送

7.2 前後端如何進行通信呢?

  1. Ajax(有同源策略限制);Fetch API則是XMLHttpRequest的最新替代技術, 它是W3C的正式標準
  2. WebSocket:支持跨域請求數據,沒有同源策略的限制
  3. CORS:新的協議通信標準;CORS則將導致跨域訪問的請求分為三種:Simple Request,Preflighted Request以及Requests with Credential;cors相對於jsonp而言的好處就是支持所有的請求方式,不止是get請求,還支持post,put請求等等,而它的缺點就很明顯,無法相容所有的瀏覽器,對於要相容到老式瀏覽器而言,還是使用jsonp好點

7.3 如何創建Ajax呢?

  1. XMLHttpRequest對象的工作流程
  2. 瀏覽器的相容性處理【重點】
  3. 事件的觸發條件
  4. 事件的觸發順序
  function ajax(params){
    // 1. 創建對象,考慮相容性【重點】
    var xhr = XMLHTTPRequest ? new XMLHTTPRequest() : new window.ActiveXObject('Microsoft.XMLHTTP');      // *** 相容性問題必須考慮
    // 2. 打開連接
    var type = params.type || 'GET',
        url = params.url || '',
        data = params.data || {},
        success = params.success,
        error = params.error,
        dataArr = [];
    for (var k in data) {
      dataArr.push(k + '=' + data[k]);
    }
    //帶上Cookie
    xhr.withCredentials = true;
    if (type.toUpperCase() === 'GET') {
      // get
      url += '?' + dataArr.join('&');
      // 問號結尾的話,直接替換為空字元串
      xhr.open(type, url.replace(/\?$/g, ''), true);
      // GET 請求的話,是不需要再send方法中帶上參數的
      xhr.send();
    }
    else {
      // POST
      xhr.open(type, url, true);
      xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
      // POST 請求需要把數據放在send方法裡面, data = name=zhangsna&age=18&sex=male
      xhr.send(dataArr.join('&'));
    }
    // 開始監聽變化
    xhr.onreadystatechange = function(){
      // 這裡需要考慮強緩存和協商緩存的話直接處理,206是媒體資源的創建方式
      if (xhr.readyState === 4 && xhr.status === 200 || xhr.status === 304) {
          var res;
          if (success instanceof Function) {
            res = xhr.responseText;
            if (typeof res === 'string') {
              res = JSON.parse(res);
              // 開始執行成功的回調函數
              success.call(xhr, res);
            }
          } else {
            if (error instanceof Function) {
              // 失敗的話直接返回這個responseText中的內容信息
              error.call(xhr, res);
            }
          }
      }
    }
  }

7.4 跨域通信的幾種方式?

7.4.1 JSONP

  function jsonp(url, onsuccess, onerror, charset){
    // 1. 全局註冊一個callback
    var callbackName = 'callback' + Math.random() * 100;
    window[callbackName] = function(){
      if (onsuccess && typeof onsuccess === 'Function') {
        onsuccess(arguments[0]);
      }
    }
    // 2. 動態創建一個script標簽
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    charset && script.setAttribute('charset', charset);
    script.setAttribute('src', url);
    script.async = true;
    // 3. 開始監聽處理的過程
    script.onload = script.onreadystatechange = function(){
      if (!script.readyState || /loaded|complete/.test(script.readyState)) {
        // 4. 成功之後移除這個事件
        script.onload = script.onreadystatechange = null;
        // 刪除這個script的DOM對象(head.removeChild(script), 這個DOM節點的父節點相當於是head標簽這個父節點)
        script.parentNode && script.parentNode.removeChild(script);
        // 刪除函數或變數
        window[callbackName] = null;
      }
    }
    script.onerror = function(){
      if (onerror && typeof onerror === 'Function') {
        onerror();
      }
    }
    // 5. 開始發送這個請求(把這個標簽放在頁面中的head標簽中即可)
    document.getElementsByTagName('head')[0].appendChild(script);
  }

7.4.2 Hash

hash 改變後頁面不會刷新的

[!NOTE]
使用場景:當前的頁面A通過iframe或者frame嵌入了跨域的頁面

  // 1. A頁面中的代碼如下
  var B = document.getElementsByTagName('iframe');
  B.src = B.src + '#' + JSON.stringfy(data);
  // 2. B中的偽代碼如下
  window.onhashchange = function(){
    var data = window.location.hash;    // 接受數據
    data = JSON.parse(data);
  }

7.4.3 postMessage(HTML5中新增)

[!NOTE]
使用場景: 可以實現視窗A(A.com)向視窗B(B.com)發送信息

  // 1. 視窗B中的代碼如下
  var BWindow = window;
  BWindow.postMessage(JSON.stringfy(data), 'http://www.A.com');   
  // 2. 視窗A中代碼
  var AWindow = window;
  AWindow.addEventListener('message', function(e){
      console.log(e.origin);                  // http://www.B.com
      console.log(e.source);                  // BWindow

      e.source.postMessage('已成功收到消息');

      console.log(JSON.parse(e.data));        // data
  }, false)
  // 父視窗給子視窗發信息,需要用iframe的contentWindow屬性作為調用主體
  // 子視窗給父視窗發的信息需要使用window.top,多層iframe使用window.frameElement

7.4.4 . WebSocket

[!NOTE]
不受同源策略影響,可以直接使用

  var ws = new window.WebSocket('ws://echo.websocket.org');

  // 打開連接
  ws.onopen = function(e){
    console.log('Connection open ……');
    ws.send('Hello WebSocket!');
  }

  // 接受消息
  ws.onmessage = function(e){
    console.log('Received Message : ', e.data);
  }

  // 關閉連接
  ws.onclose = function(e){
    console.log('Connection closed');
  }

7.4.5 CORS

支持跨域通信版本的Ajax,是一種新的標準(Origin頭)【ajax的一個變種,適用於任何】

http://www.ruanyifeng.com/blog/2016/04/cors.html

  fetch('/get/name', {
    method : 'get'
  }).then(function(response){
    console.log(response);
  }).catch(function(err){
    // 出錯了;等價於then的第二個參數
  });
  // 原因:瀏覽器預設會攔截ajax請求,會根據頭中的origin消息進行判斷處理消息;Origin欄位用來說明,本次請求來自哪個源(協議 + 功能變數名稱 + 埠)。伺服器根據這個值,決定是否同意這次請求。JSONP只支持GET請求,CORS支持所有類型的HTTP請求。JSONP的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
7.4.5.1 CORS請求的基本流程
  1. 對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭信息之中,增加一個Origin欄位。
  2. Origin欄位用來說明,本次請求來自哪個源(協議 + 功能變數名稱 + 埠)。伺服器根據這個值,決定是否同意這次請求。
  3. 如果Origin指定的源,不在許可範圍內,伺服器會返回一個正常的HTTP回應。瀏覽器發現,這個回應的頭信息沒有包含Access-Control-Allow-Origin欄位(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。
  4. 如果Origin指定的功能變數名稱在許可範圍內,伺服器返回的響應,會多出幾個頭信息欄位。
  Access-Control-Allow-Origin: http://api.bob.com   // 必需的欄位
  Access-Control-Allow-Credentials: true            // 可選欄位: 是否允許發送cookie
  Access-Control-Expose-Headers: FooBar
  Content-Type: text/html; charset=utf-8
  1. 簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。OPTIONS表示當前的這個請求是用來詢問的;伺服器收到"預檢"請求以後,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers欄位以後,確認允許跨源請求,就可以做出回應。
7.4.5.2 JSONP和CORS的區別?
  1. JSONP只支持GET請求,CORS支持所有類型的HTTP請求
  2. JSONP的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。

8. 安全

8.1 CSRF

8.1.1 基本概念和縮寫

CSRF: 跨站請求偽造,Cross site request forgery

8.1.2 CSRF 攻擊原理

CSRF攻擊原理

8.1.3 可以成功攻擊的條件?

  1. 目標網站存在CSRF漏洞的請求介面(一般為get請求)
  2. 目標用戶之前已經成功登錄過這個網站(留下了Cookie)

8.1.4 如何防禦呢?

  1. Token驗證:訪問伺服器介面的時候,會自動帶上這個token
  2. Referer驗證:驗證網站的頁面來源(只有我當前網站下的頁面才可以請求,對於來自其他網站的請求一律攔截)
  3. 隱藏令牌: 隱藏信息會放在header中(類似於Token)

8.2 XSS

8.2.1 基本概念和縮寫

XSS: cross-site scripting, 跨站腳本攻擊

8.2.2 XSS防禦

攻擊原理: 註入JS腳本

防禦措施: 讓JS代碼無法解析執行

8.3 CSRF和XSS的區別呢?

  1. CSRF:網站本身存在漏洞的介面,依賴這些登錄過目標網站的用戶來實現信息的竊取;
  2. XSS:向頁面中註入JS執行,JS函數體內執行目標任務;

[!NOTE]

  1. 一定要說出中文名稱,實現原理,防範措施都說出來
  2. 不要拖泥帶水,言簡意賅

9. 演算法

[!NOTE]
演算法攻略:多刷題才是硬道理!!!

二三面(知識深度面)

10. 渲染機制

10.1 什麼是DOCTYPE及作用?

  1. DTD(Document Type Definition):文檔類型定義,是一系列的語法規則,用來定義XML或者(X)HTML的文件類型。瀏覽器會使用它來判斷文檔的類型,決定使用哪一種協議來解析,以及切換瀏覽器模式;
  2. DOCTYPE: 是用來聲明文檔類型和DTD規範的,一個主要的用途是文件的合法性驗證;如果文件代碼不合法,那麼瀏覽器解析的時候就會出現一些出錯
  3. 總結:Doctype就是通知瀏覽器當前的文檔是屬於那種類型的,包含哪些DTD。
  <!--HTML5的寫法-->
  <DOCTYPE html>
  <!-- HTML 4.01  Strict
    1. 這個DTD 包含所有的HTML元素和屬性
    2. 但是不包含展示性的和棄用的元素(比如font)
  -->
  <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" >
  <!-- HTML 4.0.1 Transitional
    1. 這個DTD 包含所有的HTML元素和屬性
    2. 也包含展示性的和棄用性的元素(比如font)
  -->
  <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www.w3.org/TR/html4/loose.dtd" >

[!NOTE]
在W3C標準出來之前,不同的瀏覽器對頁面渲染有不同的標準,產生了一定的差異。這種渲染方式叫做混雜模式。在W3C標準出來之後,瀏覽器對頁面的渲染有了統一的標準,這種渲染方式叫做標準模式。<!DOCTYPE>不存在或者形式不正確會導致HTML或XHTML文檔以混雜模式呈現,就是把如何渲染html頁面的權利交給了瀏覽器,有多少種瀏覽器就有多少種展示方式。因此要提高瀏覽器相容性就必須重視<!DOCTYPE>

10.2 嚴格模式和混雜模式

[!NOTE]
嚴格模式和混雜模式都是瀏覽器的呈現模式,瀏覽器究竟使用混雜模式還是嚴格模式呈現頁面與網頁中的DTD(文件類型定義)有關,DTD裡面包含了文檔的規則。比如:loose.dtd

  • 嚴格模式:又稱標準模式,是指瀏覽器按照W3C標準來解析代碼,呈現頁面
  • 混雜模式:又稱為怪異模式或者相容模式,是指瀏覽器按照自己的方式來解析代碼,使用一種比較寬鬆的向後相容的方式來顯示頁面。

10.3 瀏覽器的渲染過程?

瀏覽器渲染過程

10.3.1 開始進行DOM解析,渲染DOM Tree

DOM樹渲染

10.3.2 開始進行CSS解析,渲染CSSOM Tree

CSSOM樹渲染

10.3.3 DOM樹和CSS樹的結合,最後會轉換為Render Tree

Render樹渲染

10.3.4 Layout的過程,計算每一個DOM元素的位置、寬度、高度等信息,最終渲染並顯示頁面到瀏覽器

Layout的過程

10.4 何時會觸發Reflow?

[!NOTE]
定義:DOM結構中每個元素都有自己的盒子模型,這些都是需要根據各種樣式來計算並根據計算結果將元素放在它該出現的位置,這個過程就是reflow;

  1. 當你增加、刪除、修改DOM節點的時候,會導致Reflow或Repaint
  2. 當你移動DOM的位置,或者設置動畫的時候
  3. 當你修改CSS樣式的時候
  4. 當你Resize視窗的時候(移動端沒有這個問題,與瀏覽器有關),或者在滾動視窗的時候
  5. 當你修改網頁的預設的字體的時候

10.5 何時回觸發Repaint?

[!NOTE]
定義:當各種盒子的位置、大小以及其他屬性,例如顏色、字體大小都確定下來以後,瀏覽器於是便按照元素各自的特性繪製了一遍,於是頁面的內容出現了,這個過程就是repaint

  1. DOM改動
  2. CSS改動

10.6 如何最大程度上的減少瀏覽器的重繪Repaint過程(頻率)呢?

10.6.1 避免在document上直接進行頻繁的DOM操作,如果確實需要可以採用off-document的方式進行

    1. 先將元素從document中刪除,完成修改之後然後再把元素放回原來的位置
    1. 將元素的display設置為none, 然後完成修改之後再把元素的display屬性修改為原來的值
    1. 如果需要創建多個DOM節點,可以使用DocumentFragment創建完畢之後一次性地加入document中去
  var frag = document.createDocumentFragment();
  frag.appendChild(dom);    /*每次創建的節點先放入DocumentFragment中*/

10.6.2 集中修改樣式

  1. 儘可能少的修改元素style上的屬性
  2. 儘量通過修改className來修改樣式(一次性修改)
  3. 通過cssText屬性來設置樣式值
  document.getElementById("d1").style.cssText = "color:red; font-size:13px;";

10.6.3 緩存Layout的屬性值

[!NOTE]
對於Layout屬性中非引用類型的值(數字型),如果需要多次訪問則可以在一次訪問時先存儲到局部變數中,之後都使用局部變數,這樣可以避免每次讀取屬性時造成瀏覽器的渲染。

  var width = el.offsetWidth;
  var scrollLeft = el.scrollLeft;

10.6.4 設置元素的position為absolute或fixed

[!NOTE]
在元素的position為static和relative時,元素處於DOM樹結構當中,當對元素的某個操作需要重新渲染時,瀏覽器會渲染整個頁面。將元素的position設置為absolute和fixed可以使元素從DOM樹結構中脫離出來獨立的存在,而瀏覽器在需要渲染時只需要渲染該元素以及位於該元素下方的元素,從而在某種程度上縮短瀏覽器渲染時間。

11. 佈局Layout?

Layout屬性包括

  1. offsetLeft、offsetTop、offsetHeight、offsetWidth: 相對於父對象的邊距信息,且返回值為數字;left獲取或設置相對於具有定位屬性(position定義為relative)的父對象的邊距信息,返回值為字元串10px
  2. scrollTop/Left/Width/Height:滾動條在各個方向上拉動的距離,返回值為數字
  3. clientTop/Left/Width/Height:瀏覽器的可視區域的大小
  4. getComputedStyle()、currentStyle(in IE):瀏覽器渲染DOM元素之後的寬度和高度等樣式信息

12. JS運行機制

12.1 如何理解JS的單線程?

看代碼,寫結果?

  // 同步任務
  console.log(1);
  // 非同步任務要掛起
  setTimeout(function(){
    console.log(2)
  }, 0);
  console.log(3)
  // out : 1 3 2
  console.log('A');
  setTimeout(function(){
    console.log('B')
  }, 0);
  while (true) {

  }

  // out : A

12.2 什麼是任務隊列?

  for (var i = 0; i < 4; i++) {
    // setTimeout , setInterval 只有在時間到了的時候,才會把這個事件放在非同步隊列中去
    setTimeout(function(){
      console.log(i);
    }, 1000);
  }
  // out : 4 4 4 4

12.3 什麼是Event Loop?

[!NOTE]
JS是單線程的,瀏覽器引擎會先來執行同步任務,遇到非同步任務之後,會把當前的這個非同步任務放在time模塊中,等到主線程中的所有的同步任務全部執行完畢之後;然後當前的這個非同步任務只有時間到了之後,才會把這個任務(回調函數)放在一個非同步隊列中;噹噹前的任務棧中的任務全部執行完畢了之後,會先去執行微任務隊列中的任務(Promise),然後等到微任務隊列中的所有任務全部執行完畢之後,再去執行process.nextTick()這個函數,等到這個函數執行完畢之後,本次的事件輪訓結束;
開啟新的執行棧,從巨集任務隊列中依次取出非同步任務,開始執行;每個巨集任務執行都會重新開啟一個新的任務執行棧

12.3.1 3個關鍵點

  1. 執行棧執行的是同步任務;
  2. 什麼時候去非同步隊列中取這個任務;
  3. 什麼時候向這個任務隊列中放入新的非同步任務

    12.3.2 非同步任務的分類

  • setTimeout, setInterval;
  • DOM事件(點擊按鈕的時候也會先去執行同步任務);
  • Promise

13. 知識點總結

  1. 理解JS的單線程的概念
  2. 理解任務隊列
  3. 理解Event Loop
  4. 理解哪些語句會翻入到非同步任務隊列
  5. 理解與放入到非同步任務隊列的時機

    13.1 頁面性能

    13.1.1 提升頁面性能的方法有哪些?

  6. 資源壓縮合併,減少HTTP請求;
  7. 非核心代碼的非同步載入 ---> 非同步載入的方式有哪些? ---> 非同步載入的區別?
  8. 利用瀏覽器的緩存 ---> 緩存的分類 ---> 緩存的原理
  9. 使用CDN加速
  10. 預解析DNS:DNS Prefetch 是一種DNS 預解析技術,當你瀏覽網頁時,瀏覽器會在載入網頁時對網頁中的功能變數名稱進行解析緩存,這樣在你單擊當前網頁中的連接時就無需進行DNS的解析,減少用戶等待時間,提高用戶體驗。(提前解析功能變數名稱,而不是點擊鏈接的時候才去進行DNS功能變數名稱解析,可以節省DNS解析需要耗費的20-120毫秒時間)

  <!-- https協議的網站,預設是關閉了DNS的預解析的,可以使用下麵的語句開啟  -->
  <meta http-equiv="x-dns-prefetch-control" content="on">
  <!-- 開始配置需要進行DNS預解析的功能變數名稱 -->
  <link rel="dns-prefetch" href="//www.zhix.net">                               <!--支持http和HTTPS-->
  <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />               <!--支持http的協議-->
  <link rel="dns-prefetch" href="http://nsclick.baidu.com" />
  <link rel="dns-prefetch" href="http://hm.baidu.com" />
  <link rel="dns-prefetch" href="http://eiv.baidu.com" />

14. 非同步載入的方式

14.1 動態腳本的載入

  var script = document.createElement('script');
  document.getElementsByTagName('head')[0].appendChild(script);

  // 沒有 defer 或 async,瀏覽器會立即載入並執行指定的腳本,“立即”指的是在渲染該 script 標簽之下的文檔元素之前,也就是說不等待後續載入的文檔元素,讀到就載入並執行。
  <script src="script.js"></script>

14.2 defer

<!-- 有 defer,載入後續文檔元素的過程將和 script.js 的載入並行進行(非同步),但是 script.js 的執行要在所有元素解析完成之後,DOMContentLoaded 事件觸發之前完成。 -->
<script defer src="myscript.js"></script>

14.3 async

  <!-- 有 async,載入和渲染後續文檔元素的過程將和 script.js 的載入與執行並行進行(非同步)。 -->
  <script async src="script.js"></script>

14.4 非同步載入的區別?

[!NOTE]

  1. defer是在HTML解析完成之後(DOMContentLoaded事件執行之後)才會執行,如果是多個,會按照載入的順序依次執行(按照順序執行)
  2. async是在載入完之後立即執行,如果是多個,執行順序和載入順序無關(與順序無關)

15. 說一下瀏覽器的緩存機制吧?

15.1 緩存的分類

[!NOTE]
緩存目的就是為了提升頁面的性能

15.1.1 強緩存

直接從本地讀取,不發送請求

    Response Headers
    cache-control: max-age=315360000(相對時間,優先順序比expires高)
    expires: Sat, 10 Mar 2029 04:01:39 GMT(絕對時間)

15.1.2 協商緩存

問一下伺服器,這個文件有沒有過期,然後再使用這個文件

    Response Headers
    last-modified: Tue, 12 Mar 2019 06:22:34 GMT(絕對時間)
    etag: "52-583dfb6f4de80"

向伺服器請求資源的時候,帶上if-Modified-Since或者if-None-Match這個請求頭,去詢問伺服器:

    Request Headers
    if-Modified-Since: Tue, 12 Mar 2019 06:22:34 GMT
    if-None-Match: "52-583dfb6f4de80"

16. 錯誤監控/如何保證前端產品的上線質量?

16.1 前端錯誤的分類?

  1. 即時運行錯誤:代碼錯誤
  2. 資源載入錯誤:圖片/css/js文件載入失敗

16.2 錯誤的捕獲方式?

16.2.1 即時運行錯誤的捕獲方式

  // 方法一:使用try catch捕獲
  try {
    // ...
  } catch (e) {
    // error
  } finally {
    // handle error
  }

  // 方法二:使用window.onerror 捕獲錯誤
  // 無法捕獲到資源載入錯誤
  window.onerror = function(msg, url, line, col, error){
    // ...
  }  
  window.addEventListener('error', function(msg, url, line, col, error){
    // ...
  })

16.2.2 資源載入錯誤(不會向上冒泡)

  // 方法一: 直接在script, img這些DOM標簽上面直接加上onerror事件
  Object.onerror = function(e){
      // ...
  }

  // 方法二:window.performace.getEntries(間接獲取資源載入錯誤的數量)
  var loadedResources = window.performance.getEntries();           // 1. 獲取瀏覽器中已經載入的所有資源(包括各個階段的詳細載入時間)
  var loaderImgs = loadedResources.filter(item => {
      return /\.jpg|png|gif|svg/.test(item.name)
  });
  var imgs = document.getElementsByTagName('img');                // 2. 獲取頁面中所有的img集合
  var len = imgs.length - loaderImgs.length;                      // 3. 載入失敗的圖片數量
  console.log('圖片載入失敗數量:', len, '條');


  // 方法三: 使用事件捕獲的方式來實現Error事件捕獲
  // 使用事件捕獲的方式來實現資源載入錯誤的事件的捕獲:window ---> document --> html --- > body ---> div ---...
  window.addEventListener('error', function (msg) {
      console.log(msg);
  }, true);

16.2.3 補充的方法

      // 使用事件捕獲的方式來實現
     window.addEventListener('error', function (msg) {
         console.log('資源載入異常成功捕獲:', msg);
     }, true);
     // 使用事件冒泡的方式是只能捕獲到運行的時候的一些異常
     window.addEventListener('error', function (e) {
         console.log('運行異常成功捕獲1:', e.message, e.filename, e.lineno, e.colno, e.error);
     }, false);

     // 這種方式是可以按照參數的方式來接受相關的參數信息
     window.onerror = function (msg, url, line, col, error) {
         console.log('運行異常成功捕獲2:', msg, url, line, col, error);
     }

16.2.4 問題的延伸:跨域的js運行錯誤可以捕獲嗎,錯誤提示是什麼?應該怎麼處理呢?

16.2.4.1 錯誤信息

JS跨域出現的錯誤

errorinfo :
Script0 error
0 row
0 col
16.2.4.2 處理方法
  1. 第一步:在script標簽上增加crossorigin屬性
  <!-- script 表情添加crossorigin屬性 -->
  <!-- 除了 script,所有能引入跨域資源的標簽包括 link 和 img 之類,都有一樣的屬性 -->
  <script crossorigin  src="http://www.lmj.com/demo/crossoriginAttribute/error.js"></script>
  1. 第二步:設置js資源響應頭'Access-Control-Allow-Origin: * ',伺服器端需要開啟
  // 伺服器可以直接設置一個響應頭信息
  res.setResponseHeader('Access-Control-Allow-Origin', 'www.lmj.com');

16.3 上報錯誤的基本原理?

  1. 採用Ajax通信的方式來上報
  2. 利用Image對象進行上報(cnzz)[重點理解掌握]
  // 下麵的兩種方式都是可以實現錯誤信息的上報功能的
  (new Image).src = 'http://www.baidu.com?name=zhangsna&age=18&sex=male'
  (new Image()).src = 'https://www.baidu.com?name=zhangsan'

17. 如何使用JS獲取客戶端的硬體信息呢?

  // IE 瀏覽器提供的獲取電腦硬體的API
  var locator = new ActiveXObject ("WbemScripting.SWbemLocator");
  var service = locator.ConnectServer(".");
  var properties = service.ExecQuery("SELECT * FROM Win32_Processor");

18. 使用window.performace 來實現用戶體驗的數據記錄呢?

[!NOTE]
可以參考性能優化章節-performance性能監控一文內容。

三四面(業務項目面)

[!NOTE]

  • 知識面要廣
  • 理解要深刻
  • 內心要誠實:沒瞭解過,問面試官有哪些資料可以學習
  • 態度要謙虛
  • 回答要靈活:把握一個度,不要和麵試官爭執對錯
    • 要學會贊美:被問住了可以回答,適當贊美(沒面試官理解的那麼深,虛心請教)

19.介紹一下你做過的項目?

項目介紹

19.1 項目介紹模板(業務能力體現)

  1. 我做過什麼業務
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在MySQL中經常出現未按照理想情況使用索引的情況,今天記錄一種Order by語句的使用導致未按預期使用索引的情況。 1. 問題現象 1.1 SQL語句: SELECT DISTINCT p.* FROM tb_name p WHERE 1=1 AND p.createDate >= '2019- ...
  • [20191122]oracel SQL parsing function qcplgte.txt--//昨天看了鏈接:https://nenadnoveljic.com/blog/memory-leak-parsing/ =>Memory Leak During Parsingqcplgteqcp ...
  • 目錄 "用法解析" "├── 1、JNI函數" "│ ├── 1.1、extern "C"" "│ ├── 1.2、JNIEXPORT、JNICALL" "│ ├── 1.3、函數名" "│ ├── 1.4、JNIEnv" "│ ├── 1.5、jobject" "├── 2、Java、JNI、C/ ...
  • 目錄 "1、基礎概念" "├──1.1、JNI" "├──1.2、NDK" "├──1.3、CMake與ndk build" "2、環境搭建" "3、Native C++ 項目(HelloWord案例)" "├── 3.1、項目創建(java、kotlin)" "├── 3.2、CMake的應用(詳 ...
  • 3. 圖層幾何學 圖層幾何學 不熟悉幾何學的人就不要來這裡了 --柏拉圖學院入口的簽名 在第二章裡面,我們介紹了圖層背後的圖片,和一些控製圖層坐標和旋轉的屬性。在這一章中,我們將要看一看圖層內部是如何根據父圖層和兄弟圖層來控制位置和尺寸的。另外我們也會涉及如何管理圖層的幾何結構,以及它是如何被自動調 ...
  • Coroutines 協程 最近在總結Kotlin的一些東西, 發現協程這塊確實不容易說清楚. 之前的那篇就寫得不好, 所以決定重寫. 反覆研究了官網文檔和各種教程博客, 本篇內容是最基礎也最主要的內容, 力求小白也能看懂並理解. Coroutines概念 Coroutines(協程), 電腦程式 ...
  • 1.Could not find an option named "androidx". Run 'flutter -h' (or 'flutter -h') for available flutter commands and options. 現象:Android studio工程新建Flutt ...
  • 一、看一下註釋即可,都是前面學到的知識,然後進行整合完成網頁的製作,未完待續,這個網易界面跨度可大三天。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>D139_FrameworkeOfNeteasyInt ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...