7月前端高頻面試題

這是我參與8月更文挑戰的第1天,活動詳情查看:8月更文挑戰javascript

本集合是高頻面試考點,而且優化精簡了答案,便於在面試中描述。php


  • HTTP && 瀏覽器
  • HTML && CSS
  • JS、TS、ES6
  • Vue
  • React
  • 構建工具 && 工程化
  • 性能優化

HTTP && 網絡

1. HTTP 和 HTTPS

1.http 和 https 的基本概念

http: 是一個客戶端和服務器端請求和應答的標準(TCP),用於從 WWW 服務器傳輸超文本到本地瀏覽器的超文本傳輸協議。
https:是以安全爲目標的 HTTP 通道,即 HTTP 下 加入 SSL 層進行加密。css

https 協議的做用:創建一個信息安全通道,來確保數據的傳輸,確保網站的真實性。html

2.http 和 https 的區別?

  • http 是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的 ssl 加密傳輸協議。
  • Https 協議須要 ca 證書,費用較高。
  • 使用不一樣的連接方式,端口也不一樣,通常,http 協議的端口爲 80,https 的端口爲 443。
  • http 的鏈接很簡單,是無狀態的。

3.https 協議的工做原理

客戶端在使用 HTTPS 方式與 Web 服務器通訊時有如下幾個步驟:前端

  1. 客戶端使用 https url 訪問服務器,則要求 web 服務器創建 ssl 連接
  2. web 服務器接收到客戶端的請求以後,會將網站的證書(證書中包含了公鑰),傳輸給客戶端
  3. 客戶端和 web 服務器端開始協商 SSL 連接的安全等級,也就是加密等級。
  4. 客戶端瀏覽器經過雙方協商一致的安全等級,創建會話密鑰,而後經過網站的公鑰來加密會話密鑰,並傳送給網站。
  5. web 服務器經過本身的私鑰解密出會話密鑰
  6. web 服務器經過會話密鑰加密與客戶端之間的通訊

4.https 協議的優缺點

  • HTTPS 協議要比 http 協議安全,可防止數據在傳輸過程當中不被竊取、改變,確保數據的完整性。
  • https 握手階段比較費時,會使頁面加載時間延長 50%,增長 10%~20%的耗電。
  • https 緩存不如 http 高效,會增長數據開銷。
  • SSL 證書也須要錢,功能越強大的證書費用越高。
  • SSL 證書須要綁定 IP,不能再同一個 ip 上綁定多個域名,ipv4 資源支持不了這種消耗。

TCP/IP網絡模型

TCP/IP模型是互聯網的基礎,它是一系列網絡協議的總稱。這些協議能夠劃分爲四層,分別爲鏈路層、網絡層、傳輸層和應用層。vue

  • 鏈路層:負責封裝和解封裝IP報文,發送和接受ARP/RARP報文等。
  • 網絡層:負責路由以及把分組報文發送給目標網絡或主機。
  • 傳輸層:負責對報文進行分組和重組,並以TCP或UDP協議格式封裝報文。
  • 應用層:負責向用戶提供應用程序,好比HTTP、FTP、Telnet、DNS、SMTP等。

image.png

TCP三次握手

  1. 第一次握手:創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
  2. 第二次握手:服務器收到syn包並確認客戶的SYN(ack=j+1),同時也發送一個本身的SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
  3. 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。
握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。
複製代碼

TCP 四次揮手

  1. 客戶端進程發出鏈接釋放報文,而且中止發送數據。釋放數據報文首部,FIN=1,其序列號爲seq=u(等於前面已經傳送過來的數據的最後一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即便不攜帶數據,也要消耗一個序號。

2)服務器收到鏈接釋放報文,發出確認報文,ACK=1,ack=u+1,而且帶上本身的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。java

3)客戶端收到服務器的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文(在這以前還須要接受服務器發送的最 後的數據)。node

4)服務器將最後的數據發送完畢後,就向客戶端發送鏈接釋放報文,FIN=1,ack=u+1,因爲在半關閉狀態,服務器極可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。react

5)客戶端收到服務器的鏈接釋放報文後,必須發出確認,ACK=1,ack=w+1,而本身的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP鏈接尚未釋放,必須通過2∗∗MSL(最長報文段壽命)的時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。webpack

6)服務器只要收到了客戶端發出的確認,當即進入CLOSED狀態。一樣,撤銷TCB後,就結束了此次的TCP鏈接。能夠看到,服務器結束TCP鏈接的時間要比客戶端早一些。

TCP和UDP的區別

  1. TCP是面向連接的,而UDP是面向無鏈接的。

  2. TCP僅支持單播傳輸,UDP 提供了單播,多播,廣播的功能。

  3. TCP的三次握手保證了鏈接的可靠性; UDP是無鏈接的、不可靠的一種數據傳輸協議,首先不可靠性體如今無鏈接上,通訊都不須要創建鏈接,對接收到的數據也不發送確認信號,發送端不知道數據是否會正確接收。

  4. UDP的頭部開銷比TCP的更小,數據傳輸速率更高實時性更好

HTTP 請求跨域問題

  1. 跨域的原理

    跨域,是指瀏覽器不能執行其餘網站的腳本。它是由瀏覽器的同源策略形成的。
    同源策略,是瀏覽器對 JavaScript 實施的安全限制,只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域。
    跨域原理,便是經過各類方式,避開瀏覽器的安全限制

  2. 解決方案

    最初作項目的時候,使用的是jsonp,但存在一些問題,使用get請求不安全,攜帶數據較小,後來也用過iframe,但只有主域相同才行,也是存在些問題,後來經過了解和學習發現使用代理和proxy代理配合起來使用比較方便,就引導後臺按這種方式作下服務器配置,在開發中使用proxy,在服務器上使用nginx代理,這樣開發過程當中彼此都方便,效率也高;如今h5新特性還有 windows.postMessage()

    • JSONP
      ajax 請求受同源策略影響,不容許進行跨域請求,而 script 標籤 src 屬性中的鏈 接卻能夠訪問跨域的 js 腳本,利用這個特性,服務端再也不返回 JSON 格式的數據,而是 返回一段調用某個函數的 js 代碼,在 src 中進行了調用,這樣實現了跨域。

      步驟:

      1. 去建立一個script標籤
      2. script的src屬性設置接口地址
      3. 接口參數,必需要帶一個自定義函數名,要否則後臺沒法返回數據
      4. 經過定義函數名去接受返回的數據
      //動態建立 script
      var script = document.createElement('script');
      
      // 設置回調函數
      function getData(data) {
          console.log(data);
      }
      
      //設置 script 的 src 屬性,並設置請求地址
      script.src = 'http://localhost:3000/?callback=getData';
      
      // 讓 script 生效
      document.body.appendChild(script);
      複製代碼

      JSONP 的缺點:
      JSON 只支持 get,由於 script 標籤只能使用 get 請求; JSONP 須要後端配合返回指定格式的數據。

    • document.domain 基礎域名相同 子域名不一樣

    • window.name 利用在一個瀏覽器窗口內,載入全部的域名都是共享一個window.name

    • CORS CORS(Cross-origin resource sharing)跨域資源共享 服務器設置對CORS的支持原理:服務器設置Access-Control-Allow-Origin HTTP響應頭以後,瀏覽器將會容許跨域請求

    • proxy代理 目前經常使用方式

    • window.postMessage() 利用h5新特性window.postMessage()

    • Websocket

Cookie、sessionStorage、localStorage 的區別

相同點

  • 存儲在客戶端

不一樣點

  • cookie數據大小不能超過4k;sessionStorage和localStorage的存儲比cookie大得多,能夠達到5M+
  • cookie設置的過時時間以前一直有效;localStorage永久存儲,瀏覽器關閉後數據不丟失除非主動刪除數據;sessionStorage數據在當前瀏覽器窗口關閉後自動刪除
  • cookie的數據會自動的傳遞到服務器;sessionStorage和localStorage數據保存在本地

瀏覽器的緩存機制 強制緩存 && 協商緩存

html文件也會緩存。項目中使用index.php,後端返回html內容,不會被緩存。

瀏覽器緩存策略:

強制緩存:(在指定時間內,瀏覽器直接使用強緩存的內容)

Expires:Thu.21 Jan 2019 23:59:59 GMT; (HTTP1.0)

Cache-Control:max-age=3600(HTTP1.1,優先級更高)

【緩存指令:no-cache須要協商緩存來驗證是否過時;no-store不緩存;public客戶端代理服務器均可以緩存;private客戶端可緩存】

協商緩存:(與服務器協商,肯定資源是否更新)

Last-Modified(服務器下發時間):Thu.21 Jan 2018 23:59:59 GMT;(HTTP1.0)

If-Modified-Since(瀏覽器詢問) 【可能時間變了,內容沒變】

Etag(服務器下發); (HTTP1.1)

If-None-Match(瀏覽器詢問)

HTML && CSS

HTML5 新特性、語義化

  1. 概念

    HTML5的語義化指的是合理正確的使用語義化的標籤來建立頁面結構。【正確的標籤作正確的事】

  2. 語義化標籤

    header nav main article section aside footer

  3. 語義化的優勢:

    • 沒CSS樣式的狀況下,頁面總體也會呈現很好的結構效果
    • 代碼結構清晰,易於閱讀,
    • 利於開發和維護 方便其餘設備解析(如屏幕閱讀器)根據語義渲染網頁。
    • 有利於搜索引擎優化(SEO),搜索引擎爬蟲會根據不一樣的標籤來賦予不一樣的權重

常見的兼容性問題

  1. 不一樣瀏覽器的標籤默認的margin和padding不同。*{margin:0;padding:0;}

  2. IE6雙邊距bug:塊屬性標籤float後,又有橫行的margin狀況下,在IE6顯示margin比設置的大。hack:display:inline;將其轉化爲行內屬性。

  3. 設置較小高度標籤(通常小於10px),在IE6,IE7中高度超出本身設置高度。hack:給超出高度的標籤設置overflow:hidden;或者設置行高line-height 小於你設置的高度。

  4. Chrome 中文界面下默認會將小於 12px 的文本強制按照 12px 顯示,可經過加入 CSS 屬性 -webkit-text-size-adjust: none; 解決。

  5. 超連接訪問事後hover樣式就不出現了,被點擊訪問過的超連接樣式再也不具備hover和active了。解決方法是改變CSS屬性的排列順序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}

CSS 盒子模型

CSS 盒模型本質上是一個盒子,它包括:邊距,邊框,填充和實際內容。CSS 中的盒子模型包括 IE 盒子模型和標準的 W3C 盒子模型。
在標準的盒子模型中,width 指 content 部分的寬度
在 IE 盒子模型中,width 表示 content+padding+border 這三個部分的寬度

故在計算盒子的寬度時存在差別:

標準盒模型: 一個塊的總寬度 = width+margin(左右)+padding(左右)+border(左右)

怪異盒模型: 一個塊的總寬度 = width+margin(左右)(既 width 已經包含了 padding 和 border 值)

BFC(塊級格式上下文)

BFC的概念

BFCBlock Formatting Context 的縮寫,即塊級格式化上下文。BFC是CSS佈局的一個概念,是一個獨立的渲染區域,規定了內部box如何佈局, 而且這個區域的子元素不會影響到外面的元素,其中比較重要的佈局規則有內部 box 垂直放置,計算 BFC 的高度的時候,浮動元素也參與計算。

BFC的原理佈局規則

  • 內部的Box會在垂直方向,一個接一個地放置
  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
  • 每一個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,不然相反
  • BFC的區域不會與float box重疊
  • BFC是一個獨立容器,容器裏面的子元素不會影響到外面的元素
  • 計算BFC的高度時,浮動元素也參與計算高度
  • 元素的類型和display屬性,決定了這個Box的類型。不一樣類型的Box會參與不一樣的Formatting Context

如何建立BFC?

  • 根元素,即HTML元素
  • float的值不爲none
  • position爲absolute或fixed
  • display的值爲inline-block、table-cell、table-caption
  • overflow的值不爲visible

BFC的使用場景

  • 去除邊距重疊現象
  • 清除浮動(讓父元素的高度包含子浮動元素)
  • 避免某元素被浮動元素覆蓋
  • 避免多列布局因爲寬度計算四捨五入而自動換行

讓一個元素水平垂直居中,到底有多少種方案?

  • 水平居中

    • 對於 行內元素 : text-align: center;

    • 對於肯定寬度的塊級元素:

      (1)width和margin實現。margin: 0 auto;

      (2)絕對定位和margin-left: -width/2, 前提是父元素position: relative

    • 對於寬度未知的塊級元素

      (1)table標籤配合margin左右auto實現水平居中。使用table標籤(或直接將塊級元素設值爲 display:table),再經過給該標籤添加左右margin爲auto。

      (2)inline-block實現水平居中方法。display:inline-block和text-align:center實現水平居中。

      (3)絕對定位+transform,translateX能夠移動自己元素的50%。

      (4)flex佈局使用justify-content:center

  • 垂直居中

    1. 利用 line-height 實現居中,這種方法適合純文字類
    2. 經過設置父容器 相對定位 ,子級設置 絕對定位,標籤經過margin實現自適應居中
    3. 彈性佈局 flex :父級設置display: flex; 子級設置margin爲auto實現自適應居中
    4. 父級設置相對定位,子級設置絕對定位,而且經過位移 transform 實現
    5. table 佈局,父級經過轉換成表格形式,而後子級設置 vertical-align 實現。(須要注意的是:vertical-align: middle使用的前提條件是內聯元素以及display值爲table-cell的元素)。

隱藏頁面中某個元素的方法

1.opacity:0,該元素隱藏起來了,但不會改變頁面佈局,而且,若是該元素已經綁定 一些事件,如click 事件,那麼點擊該區域,也能觸發點擊事件的

2.visibility:hidden,該元素隱藏起來了,但不會改變頁面佈局,可是不會觸發該元素已 經綁定的事件 ,隱藏對應元素,在文檔佈局中仍保留原來的空間(重繪)

3.display:none,把元素隱藏起來,而且會改變頁面佈局,能夠理解成在頁面中把該元素。 不顯示對應的元素,在文檔佈局中再也不分配空間(迴流+重繪)

項目怎麼作的移動端適配?flexible原理(1px問題,經過viewport)

flex + px

rem + vw

JS、TS、ES6

JS中的8種數據類型及區別

包括值類型(基本對象類型)和引用類型(複雜對象類型)

基本類型(值類型): Number(數字),String(字符串),Boolean(布爾),Symbol(符號),null(空),undefined(未定義)在內存中佔據固定大小,保存在棧內存中

引用類型(複雜數據類型): Object(對象)、Function(函數)。其餘還有Array(數組)、Date(日期)、RegExp(正則表達式)、特殊的基本包裝類型(String、Number、Boolean) 以及單體內置對象(Global、Math)等 引用類型的值是對象 保存在堆內存中,棧內存存儲的是對象的變量標識符以及對象在堆內存中的存儲地址。

JS中的數據類型檢測方案

1.typeof

console.log(typeof 1);               // number
console.log(typeof true);            // boolean
console.log(typeof 'mc');            // string
console.log(typeof function(){});    // function
console.log(typeof console.log());   // function
console.log(typeof []);              // object 
console.log(typeof {});              // object
console.log(typeof null);            // object
console.log(typeof undefined);       // undefined
複製代碼

優勢:可以快速區分基本數據類型

缺點:不能將Object、Array和Null區分,都返回object

2.instanceof

console.log(1 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false 
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true
複製代碼

優勢:可以區分Array、Object和Function,適合用於判斷自定義的類實例對象

缺點:Number,Boolean,String基本數據類型不能判斷

3.Object.prototype.toString.call()

var toString = Object.prototype.toString;
console.log(toString.call(1));                      //[object Number]
console.log(toString.call(true));                   //[object Boolean]
console.log(toString.call('mc'));                   //[object String]
console.log(toString.call([]));                     //[object Array]
console.log(toString.call({}));                     //[object Object]
console.log(toString.call(function(){}));           //[object Function]
console.log(toString.call(undefined));              //[object Undefined]
console.log(toString.call(null));                   //[object Null]
複製代碼

優勢:精準判斷數據類型

缺點:寫法繁瑣不容易記,推薦進行封裝後使用

var && let && const

ES6以前建立變量用的是var,以後建立變量用的是let/const

三者區別

  1. var定義的變量,沒有塊的概念,能夠跨塊訪問, 不能跨函數訪問。
    let定義的變量,只能在塊做用域裏訪問,不能跨塊訪問,也不能跨函數訪問。
    const用來定義常量,使用時必須初始化(即必須賦值),只能在塊做用域裏訪問,且不能修改。

  2. var能夠先使用,後聲明,由於存在變量提高;let必須先聲明後使用。

  3. var是容許在相同做用域內重複聲明同一個變量的,而let與const不容許這一現象。

  4. 在全局上下文中,基於let聲明的全局變量和全局對象GO(window)沒有任何關係 ;
    var聲明的變量會和GO有映射關係;

  5. 解決暫時性死區

暫時性死區是瀏覽器的bug:檢測一個未被聲明的變量類型時,不會報錯,會返回undefined
如:console.log(typeof a) //undefined
而:console.log(typeof a)//未聲明以前不能使用
let a

  1. let /const/function會把當前所在的大括號(除函數以外)做爲一個全新的塊級上下文,應用這個機制,在開發項目的時候,遇到循環事件綁定等相似的需求,無需再本身構建閉包來存儲,只要基於let的塊做用特徵便可解決

變量提高

當瀏覽器開闢出供代碼執行的棧內存後,代碼並無自上而下當即執行,而是繼續作了一些事情:把當前做用域中全部帶var、function關鍵字的進行提早的聲明和定義 =>變量提高機制 【預解析】

  • 帶var的只是提早聲明,沒有賦值,默認值是undefined。
  • 帶function的聲明加賦值。
  • 不帶var的a=3表示給全局設置window.a=3和在全局做用域下var a=3是同樣的;

在變量提高階段,遇到大括號判斷體等,不論條件是否成立,都要進行變量提高,而在高版本瀏覽器中,函數只聲明、不賦值。

JS垃圾回收機制

  1. 項目中,若是存在大量不被釋放的內存(堆/棧/上下文),頁面性能會變得很慢。當某些代碼操做不能被合理釋放,就會形成內存泄漏。咱們儘量減小使用閉包,由於它會消耗內存。

  2. 瀏覽器垃圾回收機制/內存回收機制:

    瀏覽器的Javascript具備自動垃圾回收機制(GC:Garbage Collecation),垃圾收集器會按期(週期性)找出那些不在繼續使用的變量,而後釋放其內存。

    標記清除:在js中,最經常使用的垃圾回收機制是標記清除:當變量進入執行環境時,被標記爲「進入環境」,當變量離開執行環境時,會被標記爲「離開環境」。垃圾回收器會銷燬那些帶標記的值並回收它們所佔用的內存空間。
    谷歌瀏覽器:「查找引用」,瀏覽器不定時去查找當前內存的引用,若是沒有被佔用了,瀏覽器會回收它;若是被佔用,就不能回收。
    IE瀏覽器:「引用計數法」,當前內存被佔用一次,計數累加1次,移除佔用就減1,減到0時,瀏覽器就回收它。

  3. 優化手段:內存優化 ; 手動釋放:取消內存的佔用便可。

    (1)堆內存:fn = null 【null:空指針對象】

    (2)棧內存:把上下文中,被外部佔用的堆的佔用取消便可。

  4. 內存泄漏

    在 JS 中,常見的內存泄露主要有 4 種,全局變量、閉包、DOM 元素的引用、定時器

做用域和做用域鏈

建立函數的時候,已經聲明瞭當前函數的做用域==>當前建立函數所處的上下文。若是是在全局下建立的函數就是[[scope]]:EC(G),函數執行的時候,造成一個全新的私有上下文EC(FN),供字符串代碼執行(進棧執行)

定義:簡單來講做用域就是變量與函數的可訪問範圍,由當前環境與上層環境的一系列變量對象組成
1.全局做用域:代碼在程序的任何地方都能被訪問,window 對象的內置屬性都擁有全局做用域。
2.函數做用域:在固定的代碼片斷才能被訪問

做用:做用域最大的用處就是隔離變量,不一樣做用域下同名變量不會有衝突。

做用域鏈參考連接通常狀況下,變量到 建立該變量 的函數的做用域中取值。可是若是在當前做用域中沒有查到,就會向上級做用域去查,直到查到全局做用域,這麼一個查找過程造成的鏈條就叫作做用域鏈。

閉包的兩大做用:保存/保護

  • 閉包的概念

    函數執行時造成的私有上下文EC(FN),正常狀況下,代碼執行完會出棧後釋放;可是特殊狀況下,若是當前私有上下文中的某個東西被上下文之外的事物佔用了,則上下文不會出棧釋放,從而造成不銷燬的上下文。 函數執行函數執行過程當中,會造成一個全新的私有上下文,可能會被釋放,可能不會被釋放,不論釋放與否,他的做用是:

(1)保護:劃分一個獨立的代碼執行區域,在這個區域中有本身私有變量存儲的空間,保護本身的私有變量不受外界干擾(操做本身的私有變量和外界沒有關係);

(2)保存:若是當前上下文不被釋放【只要上下文中的某個東西被外部佔用便可】,則存儲的這些私有變量也不會被釋放,能夠供其下級上下文中調取使用,至關於把一些值保存起來了;

咱們把函數執行造成私有上下文,來保護和保存私有變量機制稱爲閉包

閉包是指有權訪問另外一個函數做用域中的變量的函數--《JavaScript高級程序設計》

稍全面的回答: 在js中變量的做用域屬於函數做用域, 在函數執行完後,做用域就會被清理,內存也會隨之被回收,可是因爲閉包函數是創建在函數內部的子函數, 因爲其可訪問上級做用域,即便上級函數執行完, 做用域也不會隨之銷燬, 這時的子函數(也就是閉包),便擁有了訪問上級做用域中變量的權限,即便上級函數執行完後做用域內的值也不會被銷燬。

  • 閉包的特性

    • 一、內部函數能夠訪問定義他們外部函數的參數和變量。(做用域鏈的向上查找,把外圍的做用域中的變量值存儲在內存中而不是在函數調用完畢後銷燬)設計私有的方法和變量,避免全局變量的污染。

      1.1.閉包是密閉的容器,,相似於set、map容器,存儲數據的

      1.2.閉包是一個對象,存放數據的格式爲 key-value 形式

    • 二、函數嵌套函數

    • 三、本質是將函數內部和外部鏈接起來。優勢是能夠讀取函數內部的變量,讓這些變量的值始終保存在內存中,不會在函數被調用以後自動清除

  • 閉包造成的條件

    1. 函數的嵌套
    2. 內部函數引用外部函數的局部變量,延長外部函數的變量生命週期
  • 閉包的用途

    1. 模仿塊級做用域
    2. 保護外部函數的變量 可以訪問函數定義時所在的詞法做用域(阻止其被回收)
    3. 封裝私有化變量
    4. 建立模塊
  • 閉包應用場景

    閉包的兩個場景,閉包的兩大做用:保存/保護。 在開發中, 其實咱們隨處可見閉包的身影, 大部分前端JavaScript 代碼都是「事件驅動」的,即一個事件綁定的回調方法; 發送ajax請求成功|失敗的回調;setTimeout的延時回調;或者一個函數內部返回另外一個匿名函數,這些都是閉包的應用。

  • 閉包的優勢:延長局部變量的生命週期

  • 閉包缺點:會致使函數的變量一直保存在內存中,過多的閉包可能會致使內存泄漏

JS 中 this 的五種狀況

  1. 做爲普通函數執行時,this指向window
  2. 當函數做爲對象的方法被調用時,this就會指向該對象
  3. 構造器調用,this指向返回的這個對象
  4. 箭頭函數 箭頭函數的this綁定看的是this所在函數定義在哪一個對象下,就綁定哪一個對象。若是有嵌套的狀況,則this綁定到最近的一層對象上。
  5. 基於Function.prototype上的 apply 、 call 和 bind 調用模式,這三個方法均可以顯示的指定調用函數的 this 指向。apply接收參數的是數組,call接受參數列表,`` bind方法經過傳入一個對象,返回一個 this 綁定了傳入對象的新函數。這個函數的 this指向除了使用new `時會被改變,其餘狀況下都不會改變。若爲空默認是指向全局對象window。

原型 && 原型鏈

原型關係:

  • 每一個 class都有顯示原型 prototype
  • 每一個實例都有隱式原型 _ proto_
  • 實例的_ proto_指向對應 class 的 prototype

原型:  在 JS 中,每當定義一個對象(函數也是對象)時,對象中都會包含一些預約義的屬性。其中每一個函數對象都有一個prototype 屬性,這個屬性指向函數的原型對象

原型鏈:函數的原型鏈對象constructor默認指向函數自己,原型對象除了有原型屬性外,爲了實現繼承,還有一個原型鏈指針__proto__,該指針是指向上一層的原型對象,而上一層的原型對象的結構依然相似。所以能夠利用__proto__一直指向Object的原型對象上,而Object原型對象用Object.prototype.__ proto__ = null表示原型鏈頂端。如此造成了js的原型鏈繼承。同時全部的js對象都有Object的基本防範

特色:  JavaScript對象是經過引用來傳遞的,咱們建立的每一個新對象實體中並無一份屬於本身的原型副本。當咱們修改原型時,與之相關的對象也會繼承這一改變。

new運算符的實現機制

  1. 首先建立了一個新的空對象
  2. 設置原型,將對象的原型設置爲函數的prototype對象。
  3. 讓函數的this指向這個對象,執行構造函數的代碼(爲這個新對象添加屬性)
  4. 判斷函數的返回值類型,若是是值類型,返回建立的對象。若是是引用類型,就返回這個引用類型的對象。

JS中的深淺拷貝

EventLoop 事件循環

JS是單線程的,爲了防止一個函數執行時間過長阻塞後面的代碼,因此會先將同步代碼壓入執行棧中,依次執行,將異步代碼推入異步隊列,異步隊列又分爲宏任務隊列和微任務隊列,由於宏任務隊列的執行時間較長,因此微任務隊列要優先於宏任務隊列。微任務隊列的表明就是,Promise.thenMutationObserver,宏任務的話就是setImmediate setTimeout setInterval

JS運行的環境。通常爲瀏覽器或者Node。 在瀏覽器環境中,有JS 引擎線程和渲染線程,且兩個線程互斥。 Node環境中,只有JS 線程。 不一樣環境執行機制有差別,不一樣任務進入不一樣Event Queue隊列。 當主程結束,先執行準備好微任務,而後再執行準備好的宏任務,一個輪詢結束。

瀏覽器中的事件環(Event Loop)

事件環的運行機制是,先會執行棧中的內容,棧中的內容執行後執行微任務,微任務清空後再執行宏任務,先取出一個宏任務,再去執行微任務,而後在取宏任務清微任務這樣不停的循環。

  • eventLoop 是由JS的宿主環境(瀏覽器)來實現的;

  • 事件循環能夠簡單的描述爲如下四個步驟:

    1. 函數入棧,當Stack中執行到異步任務的時候,就將他丟給WebAPIs,接着執行同步任務,直到Stack爲空;
    2. 此期間WebAPIs完成這個事件,把回調函數放入隊列中等待執行(微任務放到微任務隊列,宏任務放到宏任務隊列)
    3. 執行棧爲空時,Event Loop把微任務隊列執行清空;
    4. 微任務隊列清空後,進入宏任務隊列,取隊列的第一項任務放入Stack(棧)中執行,執行完成後,查看微任務隊列是否有任務,有的話,清空微任務隊列。重複4,繼續從宏任務中取任務執行,執行完成以後,繼續清空微任務,如此反覆循環,直至清空全部的任務。

    事件循環流程

  • 瀏覽器中的任務源(task):

    • 宏任務(macrotask)
      宿主環境提供的,好比瀏覽器
      ajax、setTimeout、setInterval、setTmmediate(只兼容ie)、script、requestAnimationFrame、messageChannel、UI渲染、一些瀏覽器api

    • 微任務(microtask)
      語言自己提供的,好比promise.then
      then、queueMicrotask(基於then)、mutationObserver(瀏覽器提供)、messageChannel 、mutationObersve

Node 環境中的事件環(Event Loop)

Node是基於V8引擎的運行在服務端的JavaScript運行環境,在處理高併發、I/O密集(文件操做、網絡操做、數據庫操做等)場景有明顯的優點。雖然用到也是V8引擎,但因爲服務目的和環境不一樣,致使了它的API與原生JS有些區別,其Event Loop還要處理一些I/O,好比新的網絡鏈接等,因此Node的Event Loop(事件環機制)與瀏覽器的是不太同樣。

2020120317343116.png 執行順序以下:

  • timers: 計時器,執行setTimeout和setInterval的回調
  • pending callbacks: 執行延遲到下一個循環迭代的 I/O 回調
  • idle, prepare: 隊列的移動,僅系統內部使用
  • poll輪詢: 檢索新的 I/O 事件;執行與 I/O 相關的回調。事實上除了其餘幾個階段處理的事情,其餘幾乎全部的異步都在這個階段處理。
  • check: 執行setImmediate回調,setImmediate在這裏執行
  • close callbacks: 執行close事件的callback,一些關閉的回調函數,如:socket.on('close', ...)

setTimeout、Promise、Async/Await 的區別

  1. setTimeout

    settimeout的回調函數放到宏任務隊列裏,等到執行棧清空之後執行。

  2. Promise

    Promise自己是同步的當即執行函數, 當在executor中執行resolve或者reject的時候, 此時是異步操做, 會先執行then/catch等,當主棧完成後,纔會去調用resolve/reject中存放的方法執行。

    console.log('script start')
    let promise1 = new Promise(function (resolve) {
        console.log('promise1')
        resolve()
        console.log('promise1 end')
    }).then(function () {
        console.log('promise2')
    })
    setTimeout(function(){
        console.log('settimeout')
    })
    console.log('script end')
    // 輸出順序: script start->promise1->promise1 end->script end->promise2->settimeout
    複製代碼
  3. async/await

    async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操做完成,再執行函數體內後面的語句。能夠理解爲,是讓出了線程,跳出了 async 函數體。

    async function async1(){
       console.log('async1 start');
        await async2();
        console.log('async1 end')
    }
    async function async2(){
        console.log('async2')
    }
    
    console.log('script start');
    async1();
    console.log('script end')
    
    // 輸出順序:script start->async1 start->async2->script end->async1 end
    複製代碼

Async/Await 如何經過同步的方式實現異步

Async/Await就是一個自執行的generate函數。利用generate函數的特性把異步的代碼寫成「同步」的形式,第一個請求的返回值做爲後面一個請求的參數,其中每個參數都是一個promise對象.

Promise

ES6中的set(集合)和map(字典)的使用和對應的數據結構

Set數據結構

概念:set是ES6新增的數據結構。集合的概念是一組無序且惟一(即不重複)的項組成。set數據結構使用了與有限集合相同的數學概念,應用在計算機的數據結構中,與數組相似,但成員都是惟一的,沒有重複的值。

特色:key和value相同,沒有重複的value。只有健值,沒有健名,有點相似數組。

屬性:set.size set大小

set經常使用的方法

一、set.add(value)添加一個數據,返回Set結構自己 二、set.delete(value)刪除指定數據,表示刪除是否成功 三、set.has(value)判斷該值是否爲set成員,返回一個布爾值 四、set.clear() 清除全部數據,沒有返回值 五、set.keys()返回鍵名的遍歷器 六、set.values()返回鍵值的遍歷器 七、entries()返回鍵值對的遍歷器 八、forEach()使用回調函數的每一個成員

2. WeakSet

WeakSet 對象容許你將弱引用對象儲存在一個集合中

WeakSet 與 Set 的區別:

  • WeakSet 只能儲存對象引用,不能存放值,而 Set 對象均可以
  • WeakSet 對象中儲存的對象值都是被弱引用的,即垃圾回收機制不考慮 WeakSet 對該對象的應用,若是沒有其餘的變量或屬性引用這個對象值,則這個對象將會被垃圾回收掉(不考慮該對象還存在於 WeakSet 中),因此,WeakSet 對象裏有多少個成員元素,取決於垃圾回收機制有沒有運行,運行先後成員個數可能不一致,遍歷結束以後,有的成員可能取不到了(被垃圾回收了),WeakSet 對象是沒法被遍歷的(ES6 規定 WeakSet 不可遍歷),也沒有辦法拿到它包含的全部元素

屬性:

  • constructor:構造函數,任何一個具備 Iterable 接口的對象,均可以做參數

3.Map數據結構

Map 是一種叫作字典的數據結構,Map和對象最大的不一樣應該就是鍵能夠是任意類型

Map結構的實例有如下屬性:

1.size屬性 size屬性返回Map結構的成員總數。 2.set(key, value) 3.get(key) get方法讀取key對應的鍵值,若是找不到key,返回undefined。 4.has(key) has方法返回一個布爾值,表示某個鍵是否在Map數據結構中。 5.delete(key) delete方法刪除某個鍵,返回true。若是刪除失敗,返回false。 6.clear() clear方法清除全部成員,沒有返回值。

Map原生提供三個遍歷器生成函數和一個遍歷方法。

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回全部成員的遍歷器。
  • forEach():遍歷Map的全部成員。

須要特別注意的是,Map的遍歷順序就是插入順序。

4. WeakMap

WeakMap 對象是一組鍵值對的集合,其中的鍵是弱引用對象,而值能夠是任意

注意,WeakMap 弱引用的只是鍵名,而不是鍵值。鍵值依然是正常引用。

WeakMap 中,每一個鍵對本身所引用對象的引用都是弱引用,在沒有其餘引用和該鍵引用同一對象,這個對象將會被垃圾回收(相應的key則變成無效的),因此,WeakMap 的 key 是不可枚舉的。

屬性:

  • constructor:構造函數

方法:

  • has(key):判斷是否有 key 關聯對象
  • get(key):返回key關聯對象(沒有則則返回 undefined)
  • set(key):設置一組key關聯對象
  • delete(key):移除 key 的關聯對象

weakSet

  1. 成員都是對象
  2. 成員都是弱引用,隨時能夠消失。 能夠用來保存DOM節點,不容易形成內存泄漏
  3. 不能遍歷,方法有add, delete,has
    Map
  4. 本質上是健值對的集合,相似集合
  5. 能夠遍歷,方法不少,能夠幹跟各類數據格式轉換
    weakMap
    1.直接受對象做爲健名(null除外),不接受其餘類型的值做爲健名
  6. 健名所指向的對象,不計入垃圾回收機制
  7. 不能遍歷,方法同get,set,has,delete

簡述MVVM

什麼是MVVM?

視圖模型雙向綁定,是Model-View-ViewModel的縮寫,也就是把MVC中的Controller演變成ViewModel。Model層表明數據模型,View表明UI組件,ViewModelViewModel層的橋樑,數據會綁定到viewModel層並自動將數據渲染到頁面中,視圖變化的時候會通知viewModel層更新數據。之前是操做DOM結構更新視圖,如今是數據驅動視圖

MVVM的優勢:

1.低耦合。視圖(View)能夠獨立於Model變化和修改,一個Model能夠綁定到不一樣的View上,當View變化的時候Model能夠不變化,當Model變化的時候View也能夠不變;
2.可重用性。你能夠把一些視圖邏輯放在一個Model裏面,讓不少View重用這段視圖邏輯。
3.獨立開發。開發人員能夠專一於業務邏輯和數據的開發(ViewModel),設計人員能夠專一於頁面設計。
4.可測試

說說Vue的MVVM實現原理

  1. Vue做爲MVVM模式的實現庫的2種技術

    a. 模板解析
    b. 數據綁定

  2. 模板解析:實現初始化顯示

    a. 解析大括號表達式
    b. 解析指令

  3. 數據綁定:實現更新顯示

    a. 經過數據劫持實現

建立了兩種對象Observer和complie,先建立的Observer,後建立的complie,observer是爲了監視/劫持data中全部層次的屬性,同時還爲每一種屬性建立了另一種對象dep,dep與data中的屬性一一對應,complie做用是用來編譯模版,初始化界面,調用update對象,complie還爲每一個表達式建立了對應的watcher同時指定了更新節點的回調函數,將watcher添加到全部對應的dep中,

說說你對vue虛擬DOM的理解

什麼是虛擬dom
說白了就是以js對象的形式去添加dom元素
本質上是優化了diff算法
虛擬dom自己也有本身的缺陷他更適合批量修改dom
儘可能不要跨層級修改dom
設置key能夠最大的利用節點,避免重複渲染

1、什麼是vdom?

Virtual DOM 用JS模擬DOM結構用。JavaScript 對象結構表示 DOM 樹的結構;而後用這個樹構建一個真正的 DOM 樹, 插到文檔當中 當狀態變動的時候,從新構造一棵新的對象樹。而後用新的樹和舊的樹 進行比較,記錄兩棵樹差別 把所記錄的差別應用到所構建的真正的 DOM 樹上,視圖就 更新了。Virtual DOM 本質上就是在 JS 和 DOM 之間作了一個緩存。

創建一個與 dom 樹對應的虛擬 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那麼每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象 的屬性變化要比查詢 dom 樹的性能開銷小。

2、爲什麼要用vdom?

  1. DOM操做很是很是「rang貴」,將DOM對比操做放在JS層,提升效率

  2. DOM結構的對比,放在JS層來作(圖靈完備語言:能實現邏輯代碼的語言)

3、vdom核心函數有哪些

核心函數:
h('標籤名', {...屬性名...}, [...子元素...])
h('標籤名', {...屬性名...}, '.........')
patch(container, vnode)
patch(vnode, newVnode)

Vue底層實現原理

vue.js是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter和getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調
Vue是一個典型的MVVM框架,模型(Model)只是普通的javascript對象,修改它則試圖(View)會自動更新。這種設計讓狀態管理變得很是簡單而直觀

Observer(數據監聽器): Observer的核心是經過Object.defineProprtty()來監聽數據的變更,這個函數內部能夠定義setter和getter,每當數據發生變化,就會觸發setter。這時候Observer就要通知訂閱者,訂閱者就是Watcher

Watcher(訂閱者): Watcher訂閱者做爲Observer和Compile之間通訊的橋樑,主要作的事情是:

  1. 在自身實例化時往屬性訂閱器(dep)裏面添加本身
  2. 自身必須有一個update()方法
  3. 待屬性變更dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調

Compile(指令解析器): Compile主要作的事情是解析模板指令,將模板中變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加鑑定數據的訂閱者,一旦數據有變更,收到通知,更新試圖

vue響應式原理

level1: vue2.0中,響應式實現的核心就是 ES5的Object.defineProperty(obj, prop, descriptor). 經過Object.defineProperty()劫持data和props各個屬性的getter和setter,getter作依賴收集,setter派發更新。總體來講是一個 數據劫持 + 發佈-訂閱者模式。

level2: 具體來講, ① vue初始化階段(beforeCreate以後create以前),遍歷data/props,調用Object.defineProperty給每一個屬性加上getter、setter。② 每一個組件、每一個computed都會實例化一個watcher(固然也包括每一個自定義watcher),訂閱渲染/計算所用到的所用data/props/computed,一旦數據發生變化,setter被調用,會通知渲染watcher從新計算、更新組件。

問題4 vue組件通訊 level1: props+events 父子組件通訊(parent/parent/parent/children),vuex 任何組件通訊,事件中心emit/emit / emit/on 任何組件的通訊, attrs/attrs/attrs/listeners 後代通訊(provide / inject)。

level2: vuex運行機制:vuex的state做爲一個倉庫,提供數據驅動vue component渲染。視圖經過dispach派發actions,actions中能夠作一些異步操做。actions或者視圖經過commit提交給mutations,mutation去改變state。

level3: 源碼分析:vuex實際上是一個Vue.js插件,插件都須要提供一個install方法,install方法調用會將Vue做爲參數傳入。Vue.user(plugin)安裝插件,也就是執行插件的install方法。會在全局混入一個beforeCreate鉤子函數,把示例化的Store保存到全部組件的this.$store中。

level4: mutation改變state, 會觸發視圖改變的緣由?經過vue實現的,[實例化vue,把state做爲一個data屬性。] ↔️ 核心

v-model 是什麼?有什麼用呢?

參考回答: 一則語法糖,至關於 v-bind:value="xxx" 和 @input,意思是綁定了一個 value 屬性的值, 子組件可對 value 屬性監聽,經過$emit('input', xxx)的方式給父組件通信。本身實現 v-model 方式的組件也是這樣的思路。

談談對vue生命週期的理解?

每一個Vue實例在建立時都會通過一系列的初始化過程,vue的生命週期鉤子,就是說在達到某一階段或條件時去觸發的函數,目的就是爲了完成一些動做或者事件

  • create階段:vue實例被建立
    beforeCreate: 建立前,此時data和methods中的數據都尚未初始化
    created: 建立完畢,data中有值,未掛載
  • mount階段: vue實例被掛載到真實DOM節點
    beforeMount:能夠發起服務端請求,去數據
    mounted: 此時能夠操做DOM
  • update階段:當vue實例裏面的data數據變化時,觸發組件的從新渲染
    beforeUpdate :更新前
    updated:更新後
  • destroy階段:vue實例被銷燬
    beforeDestroy:實例被銷燬前,此時能夠手動銷燬一些方法
    destroyed:銷燬後

組件生命週期

生命週期(父子組件) 父組件beforeCreate --> 父組件created --> 父組件beforeMount --> 子組件beforeCreate --> 子組件created --> 子組件beforeMount --> 子組件 mounted --> 父組件mounted -->父組件beforeUpdate -->子組件beforeDestroy--> 子組件destroyed --> 父組件updated

加載渲染過程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

掛載階段 父created->子created->子mounted->父mounted

父組件更新階段 父beforeUpdate->父updated

子組件更新階段 父beforeUpdate->子beforeUpdate->子updated->父updated

銷燬階段 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

computed與watch

通俗來說,既能用 computed 實現又能夠用 watch 監聽來實現的功能,推薦用 computed, 重點在於 computed 的緩存功能 computed 計算屬性是用來聲明式的描述一個值依賴了其它的值,當所依賴的值或者變量 改變時,計算屬性也會跟着改變; watch 監聽的是已經在 data 中定義的變量,當該變量變化時,會觸發 watch 中的方法。

watch 屬性監聽 是一個對象,鍵是須要觀察的屬性,值是對應回調函數,主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操做,監聽屬性的變化,須要在數據變化時執行異步或開銷較大的操做時使用

computed 計算屬性 屬性的結果會被緩存,當computed中的函數所依賴的屬性沒有發生改變的時候,那麼調用當前函數的時候結果會從緩存中讀取。除非依賴的響應式屬性變化時纔會從新計算,主要當作屬性來使用 computed中的函數必須用return返回最終的結果 computed更高效,優先使用。data 不改變,computed 不更新。

使用場景 computed:當一個屬性受多個屬性影響的時候使用,例:購物車商品結算功能 watch:當一條數據影響多條數據的時候使用,例:搜索數據

組件中的data爲何是一個函數?

1.一個組件被複用屢次的話,也就會建立多個實例。本質上,這些實例用的都是同一個構造函數。 2.若是data是對象的話,對象屬於引用類型,會影響到全部的實例。因此爲了保證組件不一樣的實例之間data不衝突,data必須是一個函數。

爲何v-for和v-if不建議用在一塊兒

1.當 v-for 和 v-if 處於同一個節點時,v-for 的優先級比 v-if 更高,這意味着 v-if 將分別重複運行於每一個 v-for 循環中。若是要遍歷的數組很大,而真正要展現的數據不多時,這將形成很大的性能浪費 2.這種場景建議使用 computed,先對數據進行過濾

React/Vue 項目中 key 的做用

  • key的做用是爲了在diff算法執行時更快的找到對應的節點,提升diff速度,更高效的更新虛擬DOM;

    vue和react都是採用diff算法來對比新舊虛擬節點,從而更新節點。在vue的diff函數中,會根據新節點的key去對比舊節點數組中的key,從而找到相應舊節點。若是沒找到就認爲是一個新增節點。而若是沒有key,那麼就會採用遍歷查找的方式去找到對應的舊節點。一種一個map映射,另外一種是遍歷查找。相比而言。map映射的速度更快。

  • 爲了在數據變化時強制更新組件,以免「就地複用」帶來的反作用。

    當 Vue.js 用 v-for 更新已渲染過的元素列表時,它默認用「就地複用」策略。若是數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序,而是簡單複用此處每一個元素,而且確保它在特定索引下顯示已被渲染過的每一個元素。重複的key會形成渲染錯誤。

vue組件的通訊方式

  • props/$emit 父子組件通訊

    父->子props,子->父 $on、$emit 獲取父子組件實例 parent、children Ref 獲取實例的方式調用組件的屬性或者方法 父->子孫 Provide、inject 官方不推薦使用,可是寫組件庫時很經常使用

  • $emit/$on 自定義事件 兄弟組件通訊

    Event Bus 實現跨組件通訊 Vue.prototype.$bus = new Vue() 自定義事件

  • vuex 跨級組件通訊

    Vuex、$attrs、$listeners Provide、inject

雙向綁定實現原理

當一個Vue實例建立時,Vue會遍歷data選項的屬性,用 Object.defineProperty 將它們轉爲 getter/setter而且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化。每一個組件實例都有相應的 watcher 程序實例,它會在組件渲染的過程當中把屬性記錄爲依賴,以後當依賴項的 setter 被調用時,會通知 watcher從新計算,從而導致它關聯的組件得以更新。

v-model的實現以及它的實現原理嗎?

  1. vue中雙向綁定是一個指令v-model,能夠綁定一個動態值到視圖,同時視圖中變化能改變該值。v-model是語法糖,默認狀況下相於:value和@input
  2. 使用v-model能夠減小大量繁瑣的事件處理代碼,提升開發效率,代碼可讀性也更好
  3. 一般在表單項上使用v-model
  4. 原生的表單項能夠直接使用v-model,自定義組件上若是要使用它須要在組件內綁定value並處理輸入事件
  5. 我作過測試,輸出包含v-model模板的組件渲染函數,發現它會被轉換爲value屬性的綁定以及一個事件監聽,事件回調函數中會作相應變量更新操做,這說明神奇魔法其實是vue的編譯器完成的。

nextTick的實現

  1. nextTickVue提供的一個全局API,是在下次DOM更新循環結束以後執行延遲迴調,在修改數據以後使用$nextTick,則能夠在回調中獲取更新後的DOM
  2. Vue在更新DOM時是異步執行的。只要偵聽到數據變化,Vue將開啓1個隊列,並緩衝在同一事件循環中發生的全部數據變動。若是同一個watcher被屢次觸發,只會被推入到隊列中-次。這種在緩衝時去除重複數據對於避免沒必要要的計算和DOM操做是很是重要的。nextTick方法會在隊列中加入一個回調函數,確保該函數在前面的dom操做完成後才調用;
  3. 好比,我在幹什麼的時候就會使用nextTick,傳一個回調函數進去,在裏面執行dom操做便可;
  4. 我也有簡單瞭解nextTick實現,它會在callbacks裏面加入咱們傳入的函數,而後用timerFunc異步方式調用它們,首選的異步方式會是Promise。這讓我明白了爲何能夠在nextTick中看到dom操做結果。

nextTick的實現原理是什麼?

在下次 DOM 更新循環結束以後執行延遲迴調,在修改數據以後當即使用 nextTick 來獲取更新後的 DOM。 nextTick主要使用了宏任務和微任務。 根據執行環境分別嘗試採用Promise、MutationObserver、setImmediate,若是以上都不行則採用setTimeout定義了一個異步方法,屢次調用nextTick會將方法存入隊列中,經過這個異步方法清空當前隊列。

使用過插槽麼?用的是具名插槽仍是匿名插槽或做用域插槽

vue中的插槽是一個很是好用的東西slot說白了就是一個佔位的 在vue當中插槽包含三種一種是默認插槽(匿名)一種是具名插槽還有一種就是做用域插槽 匿名插槽就是沒有名字的只要默認的都填到這裏具名插槽指的是具備名字的

keep-alive的實現

做用:實現組件緩存,保持這些組件的狀態,以免反覆渲染致使的性能問題。 須要緩存組件 頻繁切換,不須要重複渲染

場景:tabs標籤頁 後臺導航,vue性能優化

原理:Vue.js內部將DOM節點抽象成了一個個的VNode節點,keep-alive組件的緩存也是基於VNode節點的而不是直接存儲DOM結構。它將知足條件(pruneCache與pruneCache)的組件在cache對象中緩存起來,在須要從新渲染的時候再將vnode節點從cache對象中取出並渲染。

mixin

mixin 項目變得複雜的時候,多個組件間有重複的邏輯就會用到mixin
    多個組件有相同的邏輯,抽離出來
    mixin並非完美的解決方案,會有一些問題
    vue3提出的Composition API旨在解決這些問題【追求完美是要消耗必定的成本的,如開發成本】
    場景:PC端新聞列表和詳情頁同樣的右側欄目,能夠使用mixin進行混合
    劣勢:1.變量來源不明確,不利於閱讀 2.多mixin可能會形成命名衝突 3.mixin和組件可能出現多對多的關係,使得項目複雜度變高
複製代碼

vuex是什麼?原理是什麼?怎麼使用?哪一種功能場景使用它?

狀態管理庫,相似 React 中的 Rudux

關於vuex vuex是一個專門爲vue構建的狀態集管理,主要是爲了解決組件間狀態共享的問題,強調的是數據的集中式管理,說白了主要是便於維護便於解耦因此不是全部的項目都適合使用vuex,若是你不是構建大型項目使用vuex反而使你的項目代碼繁瑣多餘

vuex的核心: state mutations getters actions modules

Vuex的理解及使用場景

Vuex 是一個專爲 Vue 應用程序開發的狀態管理模式。每個 Vuex 應用的核心就是 store(倉庫)。

  1. Vuex 的狀態存儲是響應式的;當 Vue 組件從 store 中讀取狀態的時候,

若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新 2. 改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation, 這樣使得咱們能夠方便地跟蹤每個狀態的變化 Vuex主要包括如下幾個核心模塊:

  1. State:定義了應用的狀態數據
  2. Getter:在 store 中定義「getter」(能夠認爲是 store 的計算屬性),

就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來, 且只有當它的依賴值發生了改變纔會被從新計算 3. Mutation:是惟一更改 store 中狀態的方法,且必須是同步函數 4. Action:用於提交 mutation,而不是直接變動狀態,能夠包含任意異步操做 5. Module:容許將單一的 Store 拆分爲多個 store 且同時保存在單一的狀態樹中

Vuex管理狀態的機制

1)對Vuex基本理解1)是什麼:Vuex是一個專爲Vue.js應用程序開發的狀態管理的vue插件2)做用:集中式管理vue多個組件共享的狀態和從後臺獲取的數據states幫助組件管理狀態的,基於state的還有一個計算屬性數據getters,getters是從state中讀取數據並計算的,他們兩個的數據都是給組件去讀,組件中讀取state狀態數據使用 s t o r e . s t a t e m a p S t a t e ( ) , 讀取計算屬性數據也有兩個方法是 store.state或mapState(),讀取計算屬性數據也有兩個方法是 store.getters和mapGetters();更新狀態數據涉及到actions和mutations,經過$store.dispatch或mapAction()觸發action的調用,而後actions會經過commit()觸發mutations調用,mutations則直接更新狀態;actions還能夠同後臺API進行雙向通訊。

單向數據流

「單向數據流」理念的極簡示意:

  • state:驅動應用的數據源。
  • view:以聲明方式將 state 映射到視圖 。
  • actions:響應在 view 上的用戶輸入致使的狀態變化

單向數據流過程:

簡單的單向數據流(unidirectional data flow)是指用戶訪問View,View發出用戶交互的Action,在Action裏對state進行相應更新。state更新後會觸發View更新頁面的過程。這樣數據老是清晰的單向進行流動,便於維護而且能夠預測

vue的diff算法

問題:渲染真實的DOM開銷是很大的,修改了某個數據,若是直接渲染到真實dom上會引發整個DOM樹的重繪和重排。 Virtual Dom 根據真實DOM生成的一個Virtual DOM,當Virtual DOM某個節點的數據改變後生成一個新的Vnode,而後Vnode和oldVnode做對比,發現有不同的地方就直接修改在真實的DOM上,而後使oldVnode的值爲Vnode. 注意:在採起diff算法比較的時候,只會在同層級進行,不會跨層級比較。 當數據發生改變時,set方法會讓調用Dep.notify()方法通知全部訂閱者Watcher,訂閱者就會調用patch函數給真實的DOM打補丁,更新響應的試圖。

你知道Vue3有哪些新特性嗎?它們會帶來什麼影響?

  • 性能提高

更小巧、更快速 支持自定義渲染器 支持搖樹優化:一種在打包時去除無用代碼的優化手段 支持Fragments和跨組件渲染

  • API變更

模板語法99%保持不變 原生支持基於class的組件,而且無需藉助任何編譯及各類stage階段的特性 在設計時也考慮TypeScript的類型推斷特性 重寫虛擬DOM能夠期待更多的編譯時提示來減小運行時的開銷 優化插槽生成能夠單獨渲染父組件和子組件 靜態樹提高下降渲染成本 基於Proxy的觀察者機制節省內存開銷

  • 不兼容IE11

檢測機制更加全面、精準、高效,更具可調試式的響應跟蹤

Vue3.0 編譯作了哪些優化?

a. 生成 Block tree Vue.js 2.x 的數據更新並觸發從新渲染的粒度是組件級的,單個組件內部 須要遍歷該組 件的整個 vnode 樹。在 2.0 裏,渲染效率的快慢與組件大小成正相關:組件越大,渲染 效率越慢。而且,對於一些靜態節點,又無數據更新,這些遍歷都是性能浪費。 Vue.js 3.0 作到了經過編譯階段對靜態模板的分析,編譯生成了 Block tree。 Block tree 是一個將模版基於動態節點指令切割的嵌套區塊,每一個 區塊內部的節點結構是固定的, 每一個區塊只須要追蹤自身包含的動態節點。因此,在 3.0 裏,渲染效率再也不與模板大小 成正相關,而是與模板中動態節點的數量成正相關。

b. slot 編譯優化 Vue.js 2.x 中,若是有一個組件傳入了 slot,那麼每次父組件更新的時候,會強制使子組 件 update,形成性能的浪費。 Vue.js 3.0 優化了 slot 的生成,使得非動態 slot 中屬性的更新只會觸發子組件的更新。 動態 slot 指的是在 slot 上面使用 v-if,v-for,動態 slot 名字等會致使 slot 產生運行時動 態變化可是又沒法被子組件 track 的操做。 c. diff 算法優化

Vue3.0 是如何變得更快的?(底層,源碼)

a. diff 方法優化 Vue2.x 中的虛擬 dom 是進行全量的對比。 Vue3.0 中新增了靜態標記(PatchFlag):在與上次虛擬結點進行對比的時候,值對比 帶有 patch flag 的節點,而且能夠經過 flag 的信息得知當前節點要對比的具體內容化。 b. hoistStatic 靜態提高 Vue2.x : 不管元素是否參與更新,每次都會從新建立。 Vue3.0 : 對不參與更新的元素,只會被建立一次,以後會在每次渲染時候被不停的複用。 c. cacheHandlers 事件偵聽器緩存 默認狀況下 onClick 會被視爲動態綁定,因此每次都會去追蹤它的變化可是由於是同一 個函數,因此沒有追蹤變化,直接緩存起來複用便可。 原做者姓名: 歐陽呀

2.0存在的問題 1.對原始數據進行克隆一份 2.須要分別給對象中的每一個屬性設置監聽 3.0裏面使用的是proxy監聽對象中的全部的屬性

Vue3.0 新特性

Composition API 與 React.js 中 Hooks 的異同點

a. React.js 中的 Hooks 基本使用 React Hooks 容許你 "勾入" 諸如組件狀態和反作用處理等 React 功能中。Hooks 只能 用在函數組件中,並容許咱們在不須要建立類的狀況下將狀態、反作用處理和更多東西 帶入組件中。 React 核心團隊奉上的採納策略是不反對類組件,因此你能夠升級 React 版本、在新組 件中開始嘗試 Hooks,並保持既有組件不作任何更改。 案例: useState 和 useEffect 是 React Hooks 中的一些例子,使得函數組件中也能增長狀態和 運行反作用。 咱們也能夠自定義一個 Hooks,它打開了代碼複用性和擴展性的新大門。

你都作過哪些Vue的性能優化?

編碼階段
儘可能減小data中的數據及層次結構,data中的數據都會增長getter和setter,會收集對應的watcher v-if和v-for不能連用 若是須要使用v-for給每項元素綁定事件時使用事件代理 SPA 頁面採用keep-alive緩存組件 在更多的狀況下,使用v-if替代v-show key保證惟一 使用路由懶加載、異步組件 防抖、節流 第三方模塊按需導入 長列表滾動到可視區域動態加載 圖片懶加載
SEO優化
預渲染 服務端渲染SSR 打包優化 壓縮代碼 Tree Shaking/Scope Hoisting 使用cdn加載第三方模塊 多線程打包happypack splitChunks抽離公共文件 sourceMap優化
用戶體驗
骨架屏 PWA 還能夠使用緩存(客戶端緩存、服務端緩存)優化、服務端開啓gzip壓縮等。

vue與React 的比較

相同點: 1.都是組件化開發和虛擬DOM(Virtual Dom) 2.都支持經過props進行父子組件間數據通訊 3.都支持數據驅動視圖,不直接操做DOM,更新狀態數據界面就自動更新 4.都支持服務端渲染 5.都支持native的方案,React的 React Native, Vue 的Weex

不一樣點: 1.數據綁定:vue實現了數據的雙向綁定,react的數據流動是單向的 2.組件的寫法不同,React推薦的是JSX語法,也就是把HTML和CSS都寫進JavaScript,即"all in js";vue推薦的作法是webpack+vue+loader的單文件組件格式,即html,css,js寫在同一個文件中; 3.數據狀態管理不一樣,state對象在react應用中是不可變的,須要使用setState方法更新狀態;在vue中state對象不是必須的,數據由data屬性在vue對象中管理 4.Virtual Dom不同,vue會跟蹤每一個組件的依賴關係,不須要從新渲染整個組件樹; 而對於react而言,每當應用的狀態改變時,所有的組件都會被渲染,因此react中會須要shouldComponentUpdate這個生命週期函數方法來進行控制 5.React嚴格上只針對MVC的View層,Vue則是MVVM模式

React

react中父子組件傳值

使用公共組件進行狀態提高

react中父子組件中參數互傳,子傳父是先在父組件上綁定屬性設置爲一個函數,當子組件須要給父組件傳值的時候,則經過props調用該函數將參數傳入到該函數當中,此時就能夠在父組件中的函數中接收到該參數了,這個參數則爲子組件傳過來的值

父傳子是在父組件中直接綁定一個正常的屬性,這個屬性就是指具體的值,在子組件中,用props就能夠獲取到這個值

任意組件間通訊

1.能夠new一個 Vue 的 EventBus,進行事件監聽,一邊執行監聽,一邊執行新增 VUE的eventBus 就是發佈訂閱模式,是能夠在React中使用的;

2.使用pubsub-js

3.redux

React 中 setState 何時是同步的,何時是異步的?

1.異步狀況 在React事件當中是異步操做

2.同步狀況 若是是在setTimeout事件或者自定義的dom事件中,都是同步的

3.同步狀況 自定義dom事件 屢次的異步setState,更新前會進行合併 屢次的異步setState,更新前不進行合併

生命週期

安裝
當組件的實例被建立並插入到 DOM 中時,這些方法按如下順序調用:

constructor()
static getDerivedStateFromProps()
render()
componentDidMount()

更新中
更新可能由道具或狀態的更改引發。當從新渲染組件時,這些方法按如下順序調用:

static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()

卸載
當組件從 DOM 中移除時調用此方法:

componentWillUnmount()


複製代碼

Portals

Portals 提供了一種一流的方式來將子組件渲染到存在於父組件的 DOM 層次結構以外的 DOM 節點中。結構不受外界的控制的狀況下就能夠使用portals進行建立

異步組件

// 異步懶加載
const Box = lazy(()=>import('./components/Box'));
// 使用組件的時候要用suspense進行包裹
<Suspense fallback={<div>loading...</div>}> {show && <Box/>} </Suspense>
複製代碼

immutable.js

immutable內部提供的全部數據類型,對其數據進行任意操做,操做獲得的結果是修改後的值 而且修改後的值是一個新的對象,原來的對象沒有發生任何變化。

性能優化

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

1. 概念

節流:事件觸發後,規定時間內,事件處理函數不能再次被調用。也就是說在規定的時間內,函數只能被調用一次,且是最早被觸發調用的那次。

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)); // 防抖
複製代碼

防抖:屢次觸發事件,事件處理函數只能執行一次,而且是在觸發操做結束時執行。

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. 使用場景:

節流:滾動加載更多、搜索框搜的索聯想功能、高頻點擊、表單重複提交……

防抖:搜索框搜索輸入,並在輸入完之後自動搜索、手機號,郵箱驗證輸入檢測、窗口大小 resize 變化後,再從新渲染。

項目優化

移除生產環境的控制檯打印。方案不少,esling+pre-commit、使用插件自動去除,插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最後選擇了terser-webpack-plugin,腳手架vue-cli用這個插件來開啓緩存和多線程打包,無需安裝額外的插件,僅需在configureWebpack中設置terser插件的drop_console爲true便可。最好仍是養成良好的代碼習慣,在開發基本完成後去掉無用的console,vscode中的turbo console就蠻好的。

第三方庫的按需加載。echarts,官方文檔裏是使用配置文件指定使用的模塊,另外一種使用babel-plugin-equire實現按需加載。element-ui使用babel-plugin-component實現按需引入。

公有樣式,好比對element-ui部分組件(如彈框、表格、下拉選框等)樣式的統一調整。公共組件,好比date-picker、upload-file等在element-ui提供的組件基本上作進一步的封裝。自定義組件包括preview-file、搜索框等。

先後端數據交換方面,推進項目組使用藍湖、接口文檔,與後端同窗協商,規範後臺數據返回。

雅虎軍規提到的,避免css表達式、濾鏡,較少DOM操做,優化圖片、精靈圖,避免圖片空連接等

性能問題:頁面加載性能、動畫性能、操做性能。Performance API,記錄性能數據。

winter重學前端 優化技術方案:

緩存:客戶端控制的強緩存策略

下降請求成本:DNS 由客戶端控制,隔一段時間主動請求獲取域名IP,不走系統DNS(徹底看不懂)。TCP/TLS鏈接複用,服務器升級到HTTP2,儘可能合併域名。

減小請求數:JS、CSS打包到HTML。JS控制圖片異步加載、懶加載。小型圖片使用data-uri。

較少傳輸體積:儘可能使用SVG\gradient代替圖片。根據機型和網絡情況控制圖片清晰度。對低清晰度圖片使用銳化來提高體驗。設計上避免大型背景圖。

使用CDN加速,內容分發網絡,是創建再承載網基礎上的虛擬分佈式網絡,可以將源站內容緩存到全國或全球的節點服務器上。用戶就近獲取內容,提升了資源的訪問速度,分擔源站壓力。

(二面、三面後的筆試)

一、手寫bind
二、手寫簡版promise,基礎架子,不用寫all、race等api 三、爬樓梯,leetcode-cn.com/problems/cl…(後面面試官問到了尾遞歸優化)

四、猴子吃香蕉leetcode-cn.com/problems/ko…

五、迴文字符串個數leetcode-cn.com/problems/pa…(這道題出現頻率很高,朋友面試的時候也遇到了,最長迴文子字符串)

二、說一下原型鏈,原型鏈實現繼承。

四、緩存相關(對比緩存?強緩存?對應請求頭)cookie有哪些屬性?

七、說說commonjs和esmodule?

一、項目相關問題,項目仍是須要好好準備。問得有點仔細

遇到過哪些難點?怎麼解決的?作過哪些優化?優化有量化嗎?用過哪些loader?plugin?你寫的這個插件實現了什麼?怎麼實現的?sourcemap原理知道嗎?(shabi了,由於瞄過一個博客,說知道一點,說了個vlq編碼,而後被問得很尷尬,不會直接說不會就好)

二、http和tcp、https、http2(隊頭阻塞?解決了哪些問題?哪有哪些問題未解決?tcp和udp?)。摘要算法和對稱加密、非對稱加密大概說一下?摘要和加密的區別?知道哪些加密算法?websocket的使用場景(socket.io降級)?

三、前端安全防範措施?xss攻擊和csrf攻擊?\

四、怎麼看待virtual dom?ast語法樹瞭解嗎?vue-loader作了哪些事情?vue diff?vue computed和watch區別?computed怎麼實現的緩存(dirty)?vue3雙向數據綁定實現?createRender?和vue2有哪些不一樣,提到了函數式編程,說下對函數式編程對的理解。(答得很垃圾,vue3瞭解很少,尤大的直播沒認真看)

五、對MVC (react) MVVM(vue)的瞭解

六、node相關問題,node的事件循環機制?stream兩種模式的區別?看過koa源碼都會以爲和express有很大不一樣,說一下?

七、你寫太小程序,說下和寫vue有什麼區別?而後我說setData會有性能問題(react中setState會有這個問題嗎?又給本身挖坑了) 說下jsbrige?

八、時針和分針的夾角? 九、爲何要離職?怎麼學習的?有什麼問題嗎?

第 10 題:介紹下深度優先遍歷和廣度優先遍歷,如何實現?

解析:第 5 題

第 11 題:請分別用深度優先思想和廣度優先思想實現一個拷貝函數?

解析:第 6 題 一、項目相關問題? 四、團隊協做,之前的開發流程? 五、職業規劃? 六、有什麼問題嗎?

文中若有錯誤,歡迎在評論區指正,若是這篇文章幫到了你,歡迎點贊👍和關注😊

相關文章
相關標籤/搜索