2019年我總結的前端面試題


title: 2019年我總結的面試題 date: 2019-05-11 14:43:09 tags:

說一下Promise

Promise是什麼?

  • Promise是一種用於解決異步問題的思路、方案或者對象方式。

Promise怎麼用?

  • Promise是一個對象,因此先用new的方式建立一個,而後給它傳一個函數做爲參數,這個函數有兩個參數,一個叫reolve,另外一個叫reject、 緊接着,就用then來進行調用

Promise原理

  • 在Promise內部,有一個狀態管理器的存在,有三種狀態: pending、fulfilled、rejectedjavascript

    (1) promise初始化狀態爲pendinghtml

    (2) 當前調用resolve(成功), 會由pending => fulfilledvue

    (3) 當調用reject(失敗), 會由pending => rejectedjava

跨域

什麼是跨域

協議、端口和域名不一致致使的跨域 跨域是由於瀏覽器須要遵照同源策略,發出的請求即便相應成功,也被瀏覽器攔截下來node

同源策略

同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互、這是一個用於隔離潛在惡意文件的重要安全機制、nginx

爲何

若是缺乏了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。面試

一、 防護 XSS 攻擊vuex

  • XSS,即 Cross Site Script,中譯是跨站腳本攻擊。
  • HttpOnly 防止劫取 Cookie
  • 用戶的輸入檢查
  • 服務端的輸出檢查

二、防護 CSRF 攻擊數據庫

  • CSRF,即 Cross Site Request Forgery,中譯是跨站請求僞造,是一種劫持受信任用戶向服務器發送非預期請求的攻擊方式。
  • 驗證碼
  • Referer Check
  • Token驗證

跨域的解決方案

一、經過jsonp跨域 二、document.domain + iframe跨域 三、location.hash + iframe 四、window.name + iframe跨域 五、postMessage跨域 六、跨域資源共享(CORS) 七、nginx代理跨域 八、nodejs中間代理跨域 九、WebSocket協議跨域json

jsonp原理

jsonp的核心則是動態添加 script 標籤調用服務器提供的js腳本,容許用戶傳遞一個callback參數給服務器,而後服務器返回數據時會將這個callback參數做爲函數名老包裹JSON數據,這樣客戶端就能夠隨意定製本身的函數來自動處理返回數據了

  • 僅支持GET方法

如何進行網站性能優化

一、Content方面

  • 減小HTTP請求:合併文件、CSS精靈、inline image
  • 減小DNS查詢: DNS查詢完以前瀏覽器不能從這個主機下載任何文件、方法:DNS緩存、講資源分佈到恰當的數量的主機名,平衡並行下載和DNS查詢
  • 避免重定向 : 多餘的中間訪問
  • 使用AJAX緩存
  • 非必須組件延遲加載
  • 將來所需組件預加載
  • 減小DOM元素數量
  • 將資源放到不一樣的域下面:瀏覽器同時從一個域下載資源的數目有限,增長域能夠提升並行下載量
  • 減小iframe數量
  • 不要404

二、Server方面

  • 使用CDN
  • 添加Expires或者Cache-Control: 當Cache-Control和Expires同時存在時,Cache-Control會覆蓋Expires。相關連接
  • 使用Gzip壓縮
  • 配置Etag
  • Flush Buffer Early
  • Ajax使用GET進行請求
  • 避免空src的img標籤

三、Cookie方面

  • 減少Cookie
  • 引入資源的域名不要包含cookie

四、CSS方面

  • 將樣式表放到頂部
  • 不要使用CSS表達式
  • 不使用@import
  • 不使用IE的Filter

五、JavaScript

  • 將腳本放到頁面的底部
  • 將JavaScript和CSS從外部引入
  • 壓縮JavaScript和CSS
  • 刪除不須要的腳本
  • 減小DOM的查詢
  • 合理設計事件監聽器

六、圖片方面

  1. 優化圖片: 根據實際顏色須要選擇色深、壓縮
  2. 優化CSS精靈
  3. 不要在HTML中拉伸圖片
  4. 保證favicon、ico小而且可緩存

七、移動方面

  • 保證組件小於25K
  • Pack Components into a Multipart Document

從瀏覽器地址欄輸入url到顯示頁面的步驟(以HTTP爲例)

大概流程

  • URL輸入
  • DNS解析
  • TCP鏈接
  • 發送HTTP請求
  • 服務器處理請求
  • 服務器響應請求
  • 瀏覽器解析渲染頁面
  • 鏈接結束

一、在瀏覽器數地址欄輸入URL

二、瀏覽器查看緩存,若是請求資源在緩存中而且新鮮,跳轉到轉碼步驟

  • 若是資源爲緩存,發起新請求
  • 若是已緩存,檢驗是否足夠新鮮,足夠新鮮直接提供給客戶端,不然與服務器進行驗證。
  • 檢驗新鮮一般有兩個HTTP頭進行控制 ExpiresCache-Control
    • HTTP1.0提供Expires,值爲一個絕對值表示
    • HTTP1.1增長了Cache-Control : max-age=,值爲以秒爲單位的最大新鮮時間

三、瀏覽器解析URL獲取協議,主機,端口,path

四、瀏覽器組裝一個HTTP(GET)請求報文

五、瀏覽器獲取主機ip地址,過程以下:

  • 瀏覽器緩存
  • 本機緩存
  • hosts文件
  • 路由器緩存
  • ISP DNS緩存
  • DNS遞歸查詢(可能存在負載均衡致使每次IP不同)

六、打開一個sokcet與目標地址,端口創建TCP連接, 三次握手以下:

  • 客戶端發送一個TCP的SYN=1,Seq=X的包到服務器端口
  • 服務器發送SYN=1,ACK=X+1,Seq=Y的響應包
  • 客戶端發送ACK=Y+1,Seq=Z

七、TCP連接創建後發送HTTP請求

八、服務器接受請求並解析,將請求轉發到服務程序,如虛擬機使用HTTP Host頭部判斷請求的服務程序

九、服務器檢查HTTP請求頭是否包含緩存驗證信息若是驗證緩存新鮮,返回304等對應狀態碼

十、處理程序讀取完整請求並準備HTTP響應,可能須要查詢數據庫等操做

十一、服務器將響應報文經過TCP連接發送回瀏覽器

十二、瀏覽器接受HTTP響應,而後根據狀況選擇關閉TCP鏈接或者保留重用,關閉TCP鏈接的四次握手以下:

  • 主動發送Fin=1,Ack=Z,Seq=X報文
  • 被動發送ACK=X+1,Seq=Z報文
  • 被動發送Fin=1,ACK=X,Seq=Y報文
  • 主動發送ACK=Y,Seq=X報文

1三、瀏覽器檢查響應狀態碼:是否爲1XX、3XX、4XX、5XX,這些狀況處理與2XX不一樣

1四、若是資源可緩存,進行緩存

1五、對響應進行解碼(例如gzip壓縮)

1六、根據資源類型決定如何處理(假設資源爲HTML文檔)

1七、解析HTML文檔、構件DOM樹,下載資源,構造CSSOM樹,執行js腳本,這些操做沒有嚴格的前後順序,如下分別解釋

1八、構建DOM樹:

  • Tokenizing: 根據HTML規範將字符流解析爲標記
  • Lexing:詞法分析將標記轉換爲對象並定義屬性和規則
  • DOM construction: 根據HTML標記關係將對象組成DOM樹

1九、解析過程當中遇到圖片、樣式表、js文件,啓動下載

20、構建CSSOM樹

  • Tokenizing: 字符流轉換爲標記流
  • Node:根據標記建立節點
  • CSSOM:節點建立CSSOM樹

2一、根據DOM樹和CSSOM樹構建渲染樹:

  • 從DOM樹的根節點遍歷全部可見節點,不可見節點包括:1)script,meta這樣自己不可見的標籤。2)被CSS隱藏的節點,入display:none
  • 對每個可節點,找到恰當的CSSOM規則並應用
  • 發佈可視節點的內容和計算樣式

2二、js解析以下

  • 瀏覽器建立Document對象並解析HTML,將解析到的元素和文本節點添加到文檔中,此時document.readystate爲loading
  • HTML解析器遇到沒有async和defer的script時,將他們添加到文檔中,而後執行行內或者外部腳本。這些腳本同步執行,而且在腳本下載和執行時解析器會暫停。這樣就能夠用document.write()把文本插入到輸入流中。同步腳本常常定義爲函數和註冊事件處理事件,他們能夠遍歷和操做script和他們以前的文檔內容。
  • 當解析器遇到設置了async屬性的script時,開始下載腳本並繼續解析文檔。腳本在它下載完成後儘快執行,可是解析器不會停下來等它下載異步腳本禁止使用document.write(),它們能夠訪問本身script和以前的文檔元素
  • 全部deter腳本會按照在文檔上出現的順序執行,延遲腳本能訪問完整文檔時,禁止使用document.write()
  • 瀏覽器在Document對象上觸發DOMContentLoaded事件
  • 此時文檔完成解析完成,瀏覽器可能還在等待如圖片等內容加載,等這些內容完成載入而且全部異步腳本完成和執行,document.readState變爲complete,window觸發load事件

2三、顯示頁面(HTML解析過程當中會逐步顯示頁面)

移動端開發自適應頁面如何作?

一、經過meta標籤設置viewport,移動端的理想適口。

  • <meta name="viewport" content="width=width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

二、設置rem單位來進行適配、加上Flex佈局、百分比佈局

三、其它方案,響應式適配、vw+rem

rem原理

  • rem是是指相對於根元素的字體大小的單位
  • 好比設置html font-size=100px;那麼1rem=100px;以後的全部元素均可以用這個基準值來設置大小;
  • rem做用於非根元素時,相對於根元素字體大小;rem做用於根元素字體大小時,相對於其出初始字體大小——MDN

說一下this

JavaScript 函數中的 this 指向並非在函數定義的時候肯定的,而是在調用的時候肯定的。換句話說,函數的調用方式決定了 this 指向。 函數調用的方式

  • 直接調用 直接調用,就是經過 函數名(...) 這種方式調用
  • 方法調用 方法調用是指經過對象來調用其方法函數,它是 **對象.方法函數(...)** 這樣的調用形式
  • new關鍵字調用
  • 經過 bind() 將函數綁定到對象以後再進行調用
  • 經過 call()、apply() 進行調用

箭頭函數的特色?

官方解釋:箭頭函數表達式的語法比函數表達式更簡潔,而且沒有本身的this,arguments,supernew.target。

  • 引用箭頭函數有兩個方面的做用:更簡短函數和而且不綁定this

  • 箭頭函數不會建立this,它只會從本身的做用域鏈上一層繼承this。

  • 簡而言之,箭頭函數,永遠指向當前調用的對象

== 和 === 的區別?

  • == 會進行隱式轉換,比較前將兩個被比較的值轉換爲相同類型。而後比較兩個值是否相等
  • === 不進行隱式轉換,會比較類型和值

CSS選擇器優先級

  • 每一個選擇器都有權值,權值越大越優先
  • 繼承的樣式優先級低於自身制定樣式
  • !important優先級最高,js也沒法修改
  • 權值相同的時候,靠近元素的樣式優先級搞,順序爲內聯樣式 > 內部樣式表 > 外部樣式表

BFC

什麼是BFC

BFC就是"塊級格式化上下文"的意思,建立了BFC的元素就是一個獨立的盒子,不過只有Block-level Box 能夠參與建立BFC,它規定了內部的Block-level Box如何佈局,而且與這個獨立盒子裏的佈局不受外部影響,固然它不會影響到外面的元素。

BFC特性:

  • 內部的Box會在垂直方向,從頂部開始一個接一個地放置
  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生疊加
  • 每一個元素的margin box的左邊,與包含的 border box 的左邊相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。
  • BFC的區域不會與float box疊加
  • BFC就是頁面的一個隔離的獨立容器,容器裏面的子元素不會受影響到外面的元素,反之亦然。
  • 計算BFC的高度時,浮動元素也參與計算

如何觸發BFC

  • 根元素或包含根元素的元素
  • 浮動元素,float 除了 none 之外
  • 絕對定位元素, position 爲 absolute、fixed
  • display 爲 inline-block、table-cell、table-caption、flow-root
  • overflow 值不爲 visible 的元素
  • 彈性元素(display 爲 flex 或 inline-flex 元素的直接子元素)
  • 網格元素 (display 爲 grid 或 inline-grid 元素的直接子元素)
  • 多列容器(元素的 column-count 或 column-width 不爲 auto,包括 column-count 爲 1)
  • column-span 爲 all 的元素始終會建立一個新的BFC,即便該元素沒有包裹在一個多列容器中(標準變動,Chrome bug)

EventBus如何實現?

利用發佈/訂閱模式,發佈/訂閱模式由一個發佈者、多一個訂閱者以及一個調度中心所組成。訂閱者們先在調度中心訂閱某一事件並註冊相應的回調函數,當某一個時刻發佈者發佈了一個事件,調度中心取出訂閱了該事件的訂閱者們所註冊的回調函數來執行。

在發佈/訂閱模式中,訂閱者和發佈者並不須要關心對方的狀態,訂閱者只管訂閱事件並註冊回調、發佈者只管發佈事件,其他一切交給調度中心來調度,從而實現解耦。

Vue雙向綁定的原理

Vue是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter、getter,在數據變更時發佈消息給訂閱者,觸發響應的監聽回調。

具體步驟:

第一步:須要 Observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter。這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到數據變化。

第二步:Compile 解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖

第三步:Watcher 訂閱者是 Observe 和 Compile 之間通訊的橋樑,主要的事情是:

一、在自身實例化時往屬性訂閱器(dep)裏面添加本身

二、自身必須有一個update()

三、待屬性變更dep.notify()通知時,能調用自身的 update() 方法,並觸發 Compile 中綁定回調,則功成身退。

第四步:MVVM做爲數據綁定的入口,整合 Observe、Compile 和 Watcher 三者,經過 Observe 來監聽本身的 Model 數據變化。 經過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observe 和 Compile 之間的通訊橋樑; 達到數據變化 -> 視圖更新; 視圖交互(input) -> 數據 Model 變動的雙向綁定效果。

Vue Computed的實現原理和緩存原理

第一步:建立一個computedWathcers 空對象, 對 computed 對象遍歷,獲取計算屬性每個 userDef(自定義的函數或對象),而後嘗試獲取 userDefgetter,而且爲每個 getter 添加一個watcher

第二步:判斷遍歷 computed 對象的key,是否已經存在 dataprops 所佔用,存在則發出警告,不存在就調用 defineComputed 函數,給對應的key添加gettersetter

第三步:在調用 defineComputed 函數,會進行依賴收集 computedWatcher ,經過computedWatcher來進行派發通知,更新視圖

第四步:緩存就是在獲取 getter 數據的,判斷是否值相等,相等的話就直接返回,再也不進行更新視圖

MVVM框架是什麼?它和其它框架(Jquery)的區別是什麼?哪些場景適合?

MVVM分爲Model、View、ViewModel三者

  • Model 表明數據模型,數據和業務邏輯都在Model層中定義
  • View 表明UI視圖,負責數據展現
  • ViewModel 負責監聽 Model 中數據的改變而且控制視圖更新,處理用戶交互操做:

ModelView 並沒有直接關聯,而是經過 ViewModel 來進行聯繫的, ModelViewModel 之間有着雙向數據綁定的聯繫。所以當 Model 中的數據改變時會觸發 View 層的刷新,View 中因爲用戶交互操做而改變的數據也會在 Model 中同步

區別:這種模式實現了 Model 和 View的數據自動同步,所以開發時這須要要專一對數據的維護操做便可,而不須要本身操做dom 場景:數據操做比較多的場景,更加便捷

nextTick 實現原理

JS,是單線程的,利用JS的事件循環

事件循環大體分爲如下幾個步驟:

(1) 全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)

(2) 主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。

(3) 一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。哪些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。

(4) 主線程不斷重複上面的第三步

宏任務(macro task) 和 微任務(micro task)

先執行宏觀任務,再執行微觀

  • 宏觀任務:setTimeout、MessageChannel、postMessage、setImmediate...
  • 微觀:MutationObsever、Promise.then
for (macroTask of macroTaskQueue) {
    // 1. Handle current MACRO-TASK
    handleMacroTask();
      
    // 2. Handle all MICRO-TASK
    for (microTask of microTaskQueue) {
        handleMicroTask(microTask);
    }
}
複製代碼

nextTick原理:

  • 會有一個callbacks數組,接受nextTick的回調函數,push進去

  • 首先判斷是否支持Promise,支持則利用的Promise.then進行調用遍歷調用callbacks數組

  • 判斷是否支持 MutationObserver,支持則利用 MutationObserver 遍歷調用callbacks數組

  • 判斷是否支持 setImmediate,支持則利用 setImmediate 遍歷調用callbacks數組

  • 都不支持,則利用setTimeout進行遍歷調用 callbacks數組

面試回答 : 它的邏輯也很簡單,把傳入的回調函數 cb 壓入 callbacks 數組,最後一次性地根據 useMacroTask 條件執行 macroTimerFunc 或者是 microTimerFunc,而它們都會在下一個 tick 執行 flushCallbacks,flushCallbacks 的邏輯很是簡單,對 callbacks 遍歷,而後執行相應的回調函數。

什麼是虛擬 dom ?

VNode是對真實 DOM 的一種抽象描述,它的核心定義無非就幾個關鍵屬性,標籤名、數據、子節點、鍵值等,其它屬性都是用來擴展VNode的靈活性以及實現一些特殊 feature的。

Virtual DOM 除了它的數據結構的定義,映射到真實的 DOM 實際上要經歷 VNode的 create、diff、 patch等過程。

Vue組件之間的通訊

  • 父子組件通訊,props、emit、ref調用函數

  • 兄弟組件通訊,vuex、eventBus

說一下Vuex

vuex有哪幾種屬性?

vuex具備五種屬性: state、getter、mutation、action、module

vuex的state特性是?

  • vuex就是一個倉庫,倉庫裏面放不少對象。state就是數據存放地,對應於通常vue對象裏面的data

  • state裏面存放的數據是響應式的

vuex的getter特性是?

  • getters能夠對state進行計算操做

  • 能夠在多組件之間複用

vuex的mutation特性是?

  • action相似於mutation

  • action提價的是mutation,而是否是直接變動狀態

  • action能夠包含任何異步操做

不用vuex會帶來什麼問題?

  • 可維護性會降低,你要想修改數據,你得維護三個地方

  • 可讀性降低,由於一個組件裏的數據,你根本看不出來是從哪來的

  • 增長耦合,大量的上傳派發,會讓耦合性大大的增長,原本Vue用Component就是爲了減小耦合,如今這麼用,和組件化的初衷相背。

請詳細說下你對vue生命週期的理解?

總共分爲8個階段建立前/後,載入前/後,更新前/後,銷燬前/後

建立前/後: 在beforeCreated階段,vue實例的掛載元素el和數據對象data都爲undefined,還未初始化。在created階段,vue實例的數據對象data有了,el尚未。

載入前/後: 在beforeMount階段,vue實例的$el和data都初始化了,但仍是掛載以前爲虛擬的dom節點,data.message還未替換。在mounted階段,vue實例掛載完成,data.message成功渲染。

更新前/後: 當data變化時,會觸發beforeUpdate和updated方法。

銷燬前/後: 在執行destroy方法後,對data的改變不會觸發周期函數,說明此時vue實例已經解除了事件監聽以及和dom的綁定,可是dom結構依然存在

請說下封裝 vue 組件的過程?

首先,組件能夠提高整個項目的開發效率。可以把頁面抽象成多個相對獨立的模快,解決了咱們傳統項目開發:效率低、難維護、複用性等問題。

而後,使用Vue.extend方法建立一個組件,而後使用Vue.component方法註冊組件。子組件須要數據,能夠在props中接受定義。而子組件修改好數據後,想把數據遞給父組件。能夠採用emit方法。

Proxy 和 Object.defineProperty 的優劣?

  • Proxy有多達13種攔截方法,不限於apply、ownKeys、deleteProperty、has等等是 **Object.defineProperty()**不具有的

  • Proxy返回的是一個新對象,咱們能夠只操做新的對象達到目的,而 Object.defineProperty 只能遍歷對象屬性直接修改

  • Proxy做爲新標準將受到瀏覽器廠商重點持續的性能優化,也就是傳說中的新標準的性能紅利

  • 固然,Proxy的劣勢就是兼容性問題,並且沒法用polyfill磨平,所以Vue的做者才聲明須要等到下個大版本(3.0)才能用Proxy重寫。

聊一聊常見的瀏覽器端數據存儲方案

數據存儲方案:

  • Cookie
  • Web存儲(localStorage和sessionStorage)
  • IndexedDB

大概說一下Cookie和localStorage、sessionStorage的功能特性。問到的話,Cookie的缺點就是,存儲量少、數據大影響性能、只能儲存字符串、安全性問題、須要檢查Cookie可否使用

Flexible佈局方案的原理

  • 獲取document的適口寬度 除以 10
  • 得出 1rem = viewWidth / 10
  • 而後設置 html的font-size爲 rem + 'px'

爲何會有深拷貝和淺拷貝?平常開發中如何使用?,如何實現一個深拷貝?

/** * @desc 深拷貝,支持常見類型 * @param {Any} values * @return {Any} */
function deepClone(values) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == values || "object" != typeof values) return values;

    // Handle Date
    if (values instanceof Date) {
        copy = new Date();
        copy.setTime(values.getTime());
        return copy;
    }

    // Handle Array
    if (values instanceof Array) {
        copy = [];
        for (var i = 0, len = values.length; i < len; i++) {
            copy[i] = deepClone(values[i]);
        }
        return copy;
    }

    // Handle Object
    if (values instanceof Object) {
        copy = {};
        for (var attr in values) {
            if (values.hasOwnProperty(attr)) copy[attr] = deepClone(values[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy values! Its type isn't supported.");
}
複製代碼

若是是一個數組,就聲明一個數據組,而後循環遍歷,遞歸賦值。 若是是一個對象,就聲明一個對象,而後判斷是否子元素,遞歸賦值

除了遞歸,咱們還能夠借用JSON對象的parse和stringify

function deepClone(obj){
    let _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
    return objClone
}    
複製代碼
相關文章
相關標籤/搜索