面試自查手冊

前端面試題彙總

1.事件循環

(macro)task(又稱之爲宏任務)

能夠理解是每次執行棧執行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調並放到執行棧中執行)。javascript

瀏覽器爲了可以使得JS內部(macro)task與DOM任務可以有序的執行,會在一個(macro)task執行結束後, 在下一個(macro)task 執行開始前,對頁面進行從新渲染,流程以下:css

(macro)task->渲染->(macro)task->... (macro)task主要包含:script(總體代碼)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 環境)html

microtask(又稱爲微任務)

能夠理解是在當前 task 執行結束後當即執行的任務。也就是說,在當前task任務後,下一個task以前,在渲染以前。前端

因此它的響應速度相比setTimeout(setTimeout是task)會更快,由於無需等渲染。也就是說,在某一個macrotask執行完後,就會將在它執行期間產生的全部microtask都執行完畢(在渲染前)。html5

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 環境)java

tick

在事件循環中,每進行一次循環操做稱爲 tick,每一次 tick 的任務處理模型是比較複雜的,但關鍵步驟以下:android

執行一個宏任務(棧中沒有就從事件隊列中獲取) 執行過程當中若是遇到微任務,就將它添加到微任務的任務隊列中 宏任務執行完畢後,當即執行當前微任務隊列中的全部微任務(依次執行) 當前宏任務執行完畢,開始檢查渲染,而後GUI線程接管渲染 渲染完畢後,JS線程繼續接管,開始下一個宏任務(從事件隊列中獲取)ios

async函數中在await以前的代碼是當即執行的,遇到了await時,會將await後面的表達式執行一遍,將await後面的代碼也就是加入到microtask中的Promise隊列

2.渲染過程

dom tree + css tree = render tree
完了之後迴流 肯定每一個元素的幾何位置 重繪肯定每一個元素的像素nginx

重繪

節點的幾何屬性發生改變或者因爲樣式發生改變而不會影響佈局的,稱爲重繪, 例如outline, visibility, color、background-color等,重繪的代價是高昂的,由於瀏覽器必須驗證DOM樹上其餘節點元素的可見性。web

迴流

迴流是佈局或者幾何屬性須要改變就稱爲迴流。迴流是影響瀏覽器性能的關鍵因素,由於其變化涉及到部分頁面(或是整個頁面)的佈局更新。 一個元素的迴流可能會致使了其全部子元素以及DOM中緊隨其後的節點、祖先節點元素的隨後的迴流。 迴流一定會發生重繪,重繪不必定會引起迴流。

優化

  1. Dom操做
  2. 位置信息獲取
  3. style、class
  4. display:hidden再操做

優化:

  1. 少獲取元素的位置信息 每獲取一次都會觸發迴流
  2. 對元素樣式進行統一修改 e.g.在style.cssText上一次性修改,更改出class名
  3. 批量修改dom,能夠將元素設置爲none,將其脫離文檔流之後再更改,所有插到一個dom裏再插入這個dom
  4. 使用treansform等方法觸發gpu加速 使得css動畫不會觸發迴流

3.移動端1px問題

緣由:window.devicePixelRatio查看,移動端DPR=2 就是設備物理像素與視覺像素的比值

解決:

  1. <meta name='viewport' content='width=device-width,initial-scale=0.5'>
    複製代碼
  2. 微元素+transform 本元素position:relative:after position:absolute 寬度百分百 高度1px;background設個顏色 transform:scaleY(0.5);
  3. 若是是全邊框 寬度高度都爲百分之兩百 縮小0.5 邊框設置1px

4.雙向綁定問題:

Vue2.x:使用Object.defineProperty實現雙向綁定,其實現的功能是數據劫持,在觀察者訂閱者模式當中是觀察者的角色 此外,當觀察者發現變化時能夠告知manager,manager告知訂閱者,訂閱者對相應的作出反應(compile)。 p.s.:對於某些數組操做失靈,其採用的方法是,改寫某個數組的原型鏈,使其指向改造過的方法原型。 Vue3.x:使用Proxy來代替Object.defineProperty,優勢總結就是,劫持能力比前者強大,能夠監控整個對象,並且不會對 數組的某些操做失靈。

5.虛擬dom:

四個關鍵方法:pathch函數分爲兩種狀況初始化時,將全部的虛擬dom實現再插入到container上
第二次當虛擬dom改變時,會使用diff算法找出不一樣,使用新dom替換舊dom(同層比較,不移動
說到渲染,有個h函數,做用是將虛擬dom渲染成爲真實dom,本質是一個遞歸函數,當不是葉子節點時會不斷的
向下調用h函數,參數有標籤名,屬性,子節點;葉子節點的調用是,標籤名,屬性,text

6.diff算法:

同層遞歸順序比較 只比較同層的dom結構,比較是依次深度遞歸比較的,順序是先看此節點還在不在,再看節點屬性是否改變,再看文本內容,節點是否被替換

key的做用

  1. key的做用是爲了在diff算法執行時更快的找到對應的節點,提升diff速度。
  2. 在數據變化時強制更新組件,以免「原地複用」帶來的反作用。
  3. 主要是爲了提高diff【同級比較】的效率。本身想一下本身要實現先後列表的diff,若是對列表的每一項增長一個key,即惟一索引, 那就能夠很清楚的知道兩個列表誰少了誰沒變。而若是不加key的話,就只能一個個對比了。
  4. 會根據新節點的key去對比舊節點數組中的key,從而找到相應舊節點(這裏對應的是一個key => index 的map映射)。 若是沒找到就認爲是一個新增節點。而若是沒有key,那麼就會採用一種遍歷查找的方式去找到對應的舊節點。一種一個map映射, 另外一種是遍歷查找。相比而言。map映射的速度更快。

7.axois相關配置:

能夠配置默認的url、transformRequest、transformResponse對請求體和響應體作對應的處理、headers自定義
timeout自定義、onUploadProgres onDownloadProgress、proxy設置代理、cancelToken用於取消響應

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函數接收一個 cancel 函數做爲參數
    cancel = c;
  })
});
// 取消請求
cancel(); 
複製代碼

8.事件機制:

事件綁定:w3c事件委託 addEventListener,removeEventListener 第三個參數是false則爲冒泡 true是捕獲
事件捕獲與冒泡:捕獲是先觸發父元素再觸發子元素 阻止冒泡:e.stopPropagation()、e.cancelBubble = true 阻止默認事件:e.preventDefault()、e.returnValue = false; 事件委託:將事件綁定在父元素上能夠減小綁定的數量以及動態增減子元素都無所謂 好比 focus、blur 之類的事件自己沒有事件冒泡機制,因此沒法委託; mousemove、mouseout 這樣的事件,雖然有事件冒泡,可是隻能不斷經過位置去計算定位,對性能消耗高,所以也是不適合於事件委託的;

9.前端安全:

xss-script標籤

任何能夠輸入的地方都有可能引發,包括URL XSS 常見的注入方法:

  1. 在 HTML 中內嵌的文本中,惡意內容以 script 標籤造成注入。
  2. 在內聯的 JavaScript 中,拼接的數據突破了本來的限制(字符串,變量,方法名等)。
  3. 在標籤屬性中,惡意內容包含引號,從而突破屬性值的限制,注入其餘屬性或者標籤。
  4. 在標籤的 href、src 等屬性中,包含 javascript: (僞協議)等可執行代碼。
  5. 在 onload、onerror、onclick 等事件中,注入不受控制代碼。
  6. 在 style 屬性和標籤中,包含相似 background-image:url("javascript:..."); 的代碼(新版本瀏覽器已經能夠防範)。
  7. 在 style 屬性和標籤中,包含相似 expression(...) 的 CSS 表達式代碼(新版本瀏覽器已經能夠防範)。 --儲存型:數據庫返還數據未經轉義直接渲染 --反射型:將用戶輸入的存在XSS攻擊的數據,發送給後臺,後臺並未對數據進行存儲,也未通過任何過濾,直接返回給客戶端。被瀏覽器渲染。就可能致使XSS攻擊;

防護:客戶端求情參數:包括用戶輸入,url參數、post參數。

  1. 輸入:參數變量類型限制, 若是拼接 HTML 是必要的,就須要對於引號,尖括號,斜槓進行轉義,但這還不是很完善.想對 HTML 模板各處插入點進行充分的轉義,就須要採用合適的轉義庫. 通常是用於對於輸入格式的檢查,例如:郵箱,電話號碼,用戶名,密碼……等,按照規定的格式輸入。 不只僅是前端負責,後端也要作相同的過濾檢查。由於攻擊者徹底能夠繞過正常的輸入流程,直接利用相關接口向服務器發送設置。
  2. 輸出:
  3. httpOnly: 在 cookie 中設置 HttpOnly 屬性後,js腳本將沒法讀取到 cookie 信息。

CSRF 跨站請求僞造

csrf是讓用戶住不知情的狀況下,冒用其身份發起了一個請求

流程圖
在三方網站中,利用圖片的url來執行get請求,表單執行post請求

防範

  1. Get 請求不對數據進行修改
  2. 不讓第三方網站訪問到用戶 Cookie ——能夠對 Cookie 設置 SameSite 屬性,該屬性設置 Cookie 不隨着跨域請求發送,不是都兼容
  3. 阻止第三方網站請求接口
  4. 請求時附帶驗證信息,好比驗證碼或者 token
  5. 驗證 Referer對於須要防範 CSRF 的請求,咱們能夠經過驗證 Referer 來判斷該請求是否爲第三方網站發起的。

與XSS的差異

在後臺接收到請求的時候,能夠經過請求頭中的Referer請求頭來判斷請求來源 一般來講 CSRF 是由 XSS 實現的,CSRF 時常也被稱爲 XSRF(CSRF 實現的方式還能夠是直接經過命令行發起請求等)。 本質上講,XSS 是代碼注入問題,CSRF 是 HTTP 問題。 XSS 是內容沒有過濾致使瀏覽器將攻擊者的輸入當代碼執行。CSRF 則是由於瀏覽器在發送 HTTP 請求時候自動帶上 cookie,而通常網站的 session 都存在 cookie裏面(Token驗證能夠避免)。

iframe插件——能夠經過配置沙盒屬性來控制粒度權限、

點擊劫持經過iframez-index顯示在某小遊戲上面,iframe設置爲透明——經過X-Frame—Option:Deny、

錯誤的內容推斷,使用假的文件格式隱藏腳本內容,再次請求上傳的文件時,因爲內容推斷錯誤而致使腳本執行——X-Content-Type-Options來阻止瀏覽器自行推斷文件類型

npm第三方包可能存在xss漏洞

前端本地儲存的數據可能會由於xss漏洞被讀取

cdn劫持,當分散的腳本被劫持時,可能會加載後出現問題,能夠經過hash加密驗證匹配不匹配

10. 0.2 + 0.1 = 0.300000000004

——因爲IEEE 754標準的緣由 解決辦法能夠將結果乘1000再除1000進行一個截尾操做 parseFloat((0.1 + 0.2).toFixed(10))

11.querySelector()

方法僅僅返回匹配指定選擇器的第一個元素。若是你須要返回全部的元素,請使用 querySelectorAll() 方法替代。 因爲querySelector是按css規範來實現的,因此它傳入的字符串中第一個字符不能是數字. 最後再根據查詢的資料總結一下: query選擇符選出來的元素及元素數組是靜態的,而getElement這種方法選出的元素是動態的。 靜態的就是說選出的全部元素的數組,不會隨着文檔操做而改變. 在使用的時候getElement這種方法性能比較好,query選擇符則比較方便.

12.「==」運算符比較「喜歡」Number 先toString再valueOf

Boolean([]) //true

Boolean(undefined) // false

Boolean(null) // false 

Boolean(0) // false 

Boolean(NaN) // false 

Boolean('') // false

Number([]) // 0

Number({}) // NaN。
複製代碼

13.對於 CommonJS 和 ES6 中的模塊化的二者區別是:

前者支持動態導入,也就是 require(${path}/xx.js),後者目前不支持,可是已有提案

前者是同步導入,由於用於服務端,文件都在本地,同步導入即便卡住主線程影響也不大。然後者是異步導入,由於用於瀏覽器,須要下載文件,若是也採用同步導入會對渲染有很大影響

前者在導出時都是值拷貝,就算導出的值變了,導入的值也不會改變,因此若是想更新值,必須從新導入一次。可是後者採用實時綁定的方式,導入導出的值都指向同一個內存地址,因此導入值會跟隨導出值變化

後者會編譯成 require/exports 來執行的

14.DNS:域名服務系統

--瀏覽器搜索自身的DNS緩存: 首先瀏覽器會去搜索自身的DNS緩存,看緩存有沒有過時,過時的話緩存的解析就結束了(chrome緩存的時間只有一分鐘,查看chrome的緩存可打開:chrome:/net-internals/#dns )。 --搜索操做系統自身的DNS緩存: 若是瀏覽器沒有找到緩存或者緩存過時失效,瀏覽器就會搜索操做系統自身的緩存,沒有找到或者失效,解析結束(操做系統的緩存:window系統是一天,mac系統嚴格根DNS協議中的TTL)。 --讀取本地的hosts文件: 若操做系統的緩存也沒有找到或失效,瀏覽器就會去讀取本地的hosts文件(Hosts文件也能夠創建域名到IP地址的綁定關係,能夠經過編輯Hosts文件來達到名稱解析的的。 例如,咱們須要屏蔽某個域名時,就能夠將其地址指向一個不存在IP地址,以達到屏蔽的效果)。 --瀏覽器發起一個DNS的系統調用: hosts中沒有找到對應的配置項的話,瀏覽器發起一個DNS的調用(向本地主控DNS服務,通常來講是你的運營商提供的)。

--經過 DNS 查詢 IP 地址的操做稱爲域名解析,負責執行解析這一操做的就叫解析器。 解析器其實是一段程序,它包含在操做系統的 Socket 庫中 --調用解析器後,解析器會向 DNS 服務器(運營商提供的)發送查詢消息。 --運營商服務會先查找自身緩存找到對應條目,沒有過時,解析成功,若沒找到對應條目,主控服務器會代替瀏覽器發起一個迭代的DNS解析的請求,先查找根域的), 運營商服務器拿到域名的IP,返回給操做系統的內核,同時緩存在了本身的緩存區,操做系統內核從DNS服務商拿來的IP地址返回給瀏覽器。 --瀏覽器再向 Web 服務器發送消息時,只要從該內存地址取出 IP地址,將它與 HTTP 請求消息一塊兒交給操做系統 .

--首先運營商服務從已經配置好的信息中拿到根域名的IP地址(這裏假設根域只有一個,實際是想13個根域發起請求),而後像根域發起請求羣問:"請問http:/www.lab.glasscom.com的IP地址是多少?",根域名查詢記錄數據後沒有找到,回答:"我不知道它的IP地址,不過我知道.com的權威服務器(ns)的地址,它xxx.xxx.xxx.xxx,你去問它吧"。運營商服務運營商服務拿到.com的IP地址,根據IP地址發起另外一個請求去詢問.com服務器問:"請問 http:/www.lab.glasscom.com的ns的IP地址是多少?",.com域服務器查找自身記錄數據後回答:「我不知道,我只知道.http://glasscom.com的IP地址」。 以此類推,只要重複前面的步驟,就能夠順藤摸瓜找到目標DNS服務器,只要向目標DNS 服務器發送查詢消息,就可以獲得咱們須要的答案,也就是 http:/www.lab.glasscom.com 的 IP 地址了。

15.CDN:內容分發網絡

--而HTTP傳輸時延對web的訪問速度的影響很大,在絕大多數狀況下是起決定性做用的,這是由TCP/IP協議的一些特色決定的。物理層上的緣由是光速有限、信道有限,協議上的緣由有丟包、慢啓動、擁塞控制等。 要提升訪問速度,最簡單的作法固然就是多設置幾個服務器,讓終端用戶離服務器「更近」。典型的例子是各種下載網站在不一樣地域不一樣運營商設置鏡像站,或者是像Google那樣設置多個數據中心。可是多設幾個服務器的問題也很多,一是多地部署時的困難,二是一致性無法保障,三則是管理困難、成本很高。實際上,在排除多地容災等特殊需求的狀況下,對大多數公司這種作法是不太可取的。固然,這種方案真正作好了,甚至是比後續所說的使用CDN要好的。

CDN是一種公共服務,他自己有不少臺位於不一樣地域、接入不一樣運營商的服務器,而所謂的使用CDN實質上就是讓CDN做爲網站的門面,用戶訪問到的是CDN服務器,而不是直接訪問到網站。因爲CDN內部對TCP的優化、對靜態資源的緩存、預取,加上用戶訪問CDN時,會被智能地分配到最近的節點,下降大量延遲,讓訪問速度能夠獲得很大提高。

--原理:CDN作了兩件事,一是讓用戶訪問最近的節點,二是從緩存或者源站獲取資源 CDN有個源站的概念,源站就是提供內容的站點(網站的真實服務器), 從源站取內容的過程叫作回源。 1)、用戶向瀏覽器提供要訪問的域名; 2)、瀏覽器調用域名解析庫對域名進行解析,因爲CDN對域名解析過程進行了調整,因此解析函數庫通常獲得的是該域名對應的CNAME記錄,爲了獲得實際IP地址, 瀏覽器須要再次對得到的CNAME域名進行解析以獲得實際的IP地址;在此過程當中,使用的全局負載均衡DNS解析, 如根據地理位置信息解析對應的IP地址,使得用戶能就近訪問。 3)、這次解析獲得CDN緩存服務器的IP地址,瀏覽器在獲得實際的IP地址之後,向緩存服務器發出訪問請求; 4)、緩存服務器根據瀏覽器提供的要訪問的域名,經過Cache內部專用DNS解析獲得此域名的實際IP地址,再由緩存服務器向此實際IP地址提交訪問請求; 5)、緩存服務器從實際IP地址得獲得內容之後,一方面在本地進行保存,以備之後使用,另外一方面把獲取的數據返回給客戶端,完成數據服務過程; 6)、客戶端獲得由緩存服務器返回的數據之後顯示出來並完成整個瀏覽的數據請求過程。 經過以上的分析咱們能夠獲得,爲了實現既要對普通用戶透明(即加入緩存之後用戶客戶端無需進行任何設置,直接使用被加速網站原有的域名便可訪問, 又要在爲指定的網站提供加速服務的同時下降對ICP的影響,只要修改整個訪問過程當中的域名解析部分,以實現透明的加速服務。

16. ['1', '2', '3'].map(parseInt)

answer[1,NaN,NaN]。

why? 由於parseInt第二個參數是默認進制,map使用時默認傳入第二個參數是index,當第二個參數是0時默認是十進制,2大於一進制最大值,3大於二進制最大值

17. Set、WeakSet

Set

ES6 新增的一種新的數據結構,相似於數組,但成員是惟一且無序的,沒有重複的值。 Set 對象容許你儲存任何類型的惟一值,不管是原始值或者是對象引用。 向 Set 加入值的時候,不會發生類型轉換,因此5和"5"是兩個不一樣的值。Set 內部判斷兩個值是否不一樣,使用的算法叫作「Same-value-zero equality」, 它相似於精確相等運算符(===),主要的區別是NaN等於自身,而精確相等運算符認爲NaN不等於自身。 add(value):新增,至關於 array裏的push

delete(value):存在即刪除集合中value

has(value):判斷集合中是否存在 value

clear():清空集合

Array.from 方法能夠將 Set 結構轉爲數組

遍歷方法(遍歷順序爲插入順序) keys():返回一個包含集合中全部鍵的迭代器

values():返回一個包含集合中全部值得迭代器

entries():返回一個包含Set對象中全部元素得鍵值對迭代器

forEach(callbackFn, thisArg):用於對集合成員執行callbackFn操做,若是提供了 thisArg 參數,回調中的this會是這個參數,沒有返回值

WeakSet

WeakSet 與 Set 的區別:

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

18.Map、WeakMap

集合 與 字典 的區別:

共同點:集合、字典 能夠儲存不重複的值 不一樣點:集合 是以 [value, value]的形式儲存元素,字典 是以 [key, value] 的形式儲存

Map

const m = new Map()
const o = {p: 'haha'}
m.set(o, 'content')
m.get(o)	// content

m.has(o)	// true
m.delete(o)	// true
m.has(o)	// false
複製代碼

操做方法:

set(key, value):向字典中添加新元素 get(key):經過鍵查找特定的數值並返回 has(key):判斷字典中是否存在鍵key delete(key):經過鍵 key 從字典中移除對應的數據 clear():將這個字典中的全部元素刪除

遍歷方法:

Keys():將字典中包含的全部鍵名以迭代器形式返回 values():將字典中包含的全部數值以迭代器形式返回 entries():返回全部成員的迭代器 forEach():遍歷字典的全部成員

轉換方法

  1. Map 轉 Array
const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log([...map])	// [[1, 1], [2, 2], [3, 3]]
複製代碼
  1. Array 轉 Map
const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log(map)	// Map {1 => 1, 2 => 2, 3 => 3}
複製代碼
  1. Map 轉 Object

由於 Object 的鍵名都爲字符串,而Map 的鍵名爲對象,因此轉換的時候會把非字符串鍵名轉換爲字符串鍵名。

function mapToObj(map) {
    let obj = Object.create(null)
    for (let [key, value] of map) {
        obj[key] = value
    }
    return obj
}
const map = new Map().set('name', 'An').set('des', 'JS')
mapToObj(map)
複製代碼
  1. Object 轉 Map
function objToMap(map) {
    let map = new Map()
    for (let key of Object.keys(obj)) {
        map.set(key, obj[key])
    }
    return map
}

objToMap({'name': 'An', 'des': 'JS'})
複製代碼
  1. Map 轉 JSON
function mapToJson(map) {
    return JSON.stringify([...map])
}

let map = new Map().set('name', 'An').set('des', 'JS')
mapToJson(map)	// [["name","An"],["des","JS"]]
複製代碼
  1. JSON 轉 Map
function jsonToMap(jsonStr) {
  return objToMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"name": "An", "des": "JS"}')
複製代碼

WeakMap

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

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

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

方法:

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

Summary

Set

成員惟1、無序且不重複 [value, value],鍵值與鍵名是一致的(或者說只有鍵值,沒有鍵名) 能夠遍歷,方法有:add、delete、has

WeakSet

成員都是對象 成員都是弱引用,能夠被垃圾回收機制回收,能夠用來保存DOM節點,不容易形成內存泄漏 不能遍歷,方法有add、delete、has

Map

本質上是鍵值對的集合,相似集合 能夠遍歷,方法不少能夠跟各類數據格式轉換

WeakMap

只接受對象最爲鍵名(null除外),不接受其餘類型的值做爲鍵名 鍵名是弱引用,鍵值能夠是任意的,鍵名所指向的對象能夠被垃圾回收,此時鍵名是無效的 不能遍歷,方法有get、set、has、delete

19.Array

Are U An Array

  1. Array.isArray()
  2. Obeject.prototype.toString.call() //這種方法對於全部基本的數據類型都能進行判斷,即便是 null 和 undefined 。
  3. instanceof // instanceof 只能用來判斷對象類型,原始類型不能夠。而且全部對象類型 instanceof Object 都是 true。

數組扁平化 [[[1,2,3]]]

  1. arr.split(',')
  2. arr.flat(Infinity);

20.ES6與ES5類的區別

  1. class會相似變量提高,形成暫時性死區
  2. ES5的類中不會自動開啓嚴格模式,ES6會
  3. ES6的方法不可枚舉,ES5能夠
  4. ES6中的每個方法都不能夠做爲構造函數new一個對象
  5. ES5中能夠重寫類名,ES6不能夠

21.ES6與ES5繼承的區別

  1. 原型鏈指向的區別
// ES6
class Super {}
class Sub extends Super {}
const sub = new Sub();
Sub.__proto__ === Super;

// ES5
function Super() {}
function Sub() {}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
var sub = new Sub();
Sub.__proto__ === Function.prototype;
複製代碼
  1. this生成順序的區別 ES5 和 ES6 子類 this 生成順序不一樣。ES5 的繼承先生成了子類實例,再調用父類的構造函數修飾子類實例, ES6 的繼承先生成父類實例,再調用子類的構造函數修飾父類實例。這個差異使得 ES6 能夠繼承內置對象。因此須要使用super
function MyES5Array() {
  Array.call(this, arguments);
}

// it's useless
const arrayES5 = new MyES5Array(3); // arrayES5: MyES5Array {}

class MyES6Array extends Array {}

// it's ok
const arrayES6 = new MyES6Array(3); // arrayES6: MyES6Array(3) []
複製代碼

22.做用域鏈

做用域

負責收集並維護由全部聲明的標識符(變量、函數)組成的一系列查詢,並實施一套很是嚴格的規則,肯定當前執行的代碼對這些標識符的訪問權限。

變量查找

  1. 做用域嵌套 引擎從當前的執行做用域開始查找變量,若是找不到就向上一級繼續查找。當抵達最外層的全局做用域時,不管找到仍是沒有找到,查找過程都會中止。
  2. 做用域查找會在找到第一個匹配的標識符時中止。
  3. 在多層嵌套做用域中能夠定義同名的標識符,內部的標識符會「遮蔽」外部的標識符。
  4. 全局變量會自動變成全局對象的屬性
  5. 詞法做用域只由函數被聲明時所處的位置決定

LHS、RHS

L和R分別表明一個賦值操做的左側和右側,當變量出如今賦值操做的左側時進行LHS查詢,出如今賦值操做的非左側時進行RHS查詢。

LHS查詢(左側):找到變量的容器自己,而後對其賦值 RHS查詢(非左側):查找某個變量的值,能夠理解爲 retrieve his source value,即取到它的源值

ERROR

ReferenceError和做用域判別失敗相關,TypeError表示做用域判別成功了,可是對結果的操做是非法或不合理的。

RHS查詢在做用域鏈中搜索不到所需的變量,引擎會拋出ReferenceError異常。 非嚴格模式下,LHS查詢在做用域鏈中搜索不到所需的變量,全局做用域中會建立一個具備該名稱的變量並返還給引擎。 嚴格模式下(ES5開始,禁止自動或隱式地建立全局變量),LHS查詢失敗會拋出ReferenceError異常 在RHS查詢成功狀況下,對變量進行不合理的操做,引擎會拋出TypeError異常。(好比對非函數類型的值進行函數調用,或者引用null或undefined類型的值中的屬性)

函數做用域

  1. 屬於這個函數的所有變量均可以在整個函數的範圍內使用及複用————閉包原理、規避衝突、模塊原理
  2. 函數聲明的提高與函數表達式的提高區別————一個普通塊內部的函數聲明一般會被提高到所在做用域的頂部,不會被條件判斷所控制。儘可能避免在普通塊內部聲明函數。

塊做用域

  1. try、catch catch中會建立
  2. let——不會有變量提高、用於for循環能夠綁定每次循環的做用域
  3. const

閉包

將內部函數傳遞到所在的詞法做用域之外,它都會持有對原始定義做用域的引用,不管在何處執行這個函數都會使用閉包。

動態做用域——函數執行上下文——this

23.Koa的中間件機制

app.use()——掛載中間件 在app.listen()方法中compose函數調用了中間件對其進行處理,以後就是this.handleRequest

如何執行

  1. compose函數對中間件處理,返回fnMiddleware函數
  2. fnMiddleware的執行過程(context,next)兩個參數, 其執行中標識了變量index,表示上次執行到了哪一個函數
  3. 肯定目前要執行哪一個函數(dispach(i+1))之後對其執行結果進行promise包裝

特色

存儲:以數組形式存儲中間件。 狀態管理:全部的狀態變動,都交給ctx對象,無需跨中間件傳遞參數。 流程控制:以遞歸的方式進行中間件的執行,將下一個中間件的執行權交給正在執行的中間件,即洋蔥圈模型。 異步方案:用Promise包裹中間件的返回結果,以支持在上一個中間件內部實現Await邏輯。

24.HTTPS

區別

  1. 這是身披SSL的HTTP運行基於TCP的SSL上,添加了加密和認證機制
  2. 端口在443而非80
  3. 須要證書、共享密鑰加密和公開密鑰加密並用的混合加密機制

25.HTTP2多路複用

在 HTTP/1 中,每次請求都會創建一次TCP鏈接,也就是咱們常說的3次握手4次揮手,這在一次請求過程當中佔用了至關長的時間,即便開啓了 Keep-Alive ,解決了屢次鏈接的問題,可是依然有兩個效率上的問題:

第一個:串行的文件傳輸。當請求a文件時,b文件只能等待,等待a鏈接到服務器、服務器處理文件、服務器返回文件,這三個步驟。咱們假設這三步用時都是1秒,那麼a文件用時爲3秒,b文件傳輸完成用時爲6秒,依此類推。(注:此項計算有一個前提條件,就是瀏覽器和服務器是單通道傳輸) 第二個:鏈接數過多。咱們假設Apache設置了最大併發數爲300,由於瀏覽器限制,瀏覽器發起的最大請求數爲6(Chrome),也就是服務器能承載的最高併發爲50,當第51我的訪問時,就須要等待前面某個請求處理完成。

HTTP2採用二進制格式傳輸,取代了HTTP1.x的文本格式,二進制格式解析更高效。 多路複用代替了HTTP1.x的序列和阻塞機制,全部的相同域名請求都經過同一個TCP鏈接併發完成。在HTTP1.x中,併發多個請求須要多個TCP鏈接,瀏覽器爲了控制資源會有6-8個TCP鏈接都限制。 HTTP2中 同域名下全部通訊都在單個鏈接上完成,消除了因多個 TCP 鏈接而帶來的延時和內存消耗。 單個鏈接上能夠並行交錯的請求和響應,之間互不干擾

26.Restful接口

REST即Representational State Transfer的縮寫,可譯爲"表現層狀態轉化」。REST最大的幾個特色爲:資源、統一接口、URI和無狀態。

  1. 每個URI表明一種資源;
  2. 客戶端和服務器之間,傳遞這種資源的某種表現層;
  3. 客戶端經過四個HTTP動詞,對服務器端資源進行操做,實現"表現層狀態轉化"。
    Restful接口的流程與優勢

優勢

  1. 先後端分離,減小流量
  2. 安全問題集中在接口上,因爲接受json格式,防止了注入型等安全問題
  3. 前端無關化,後端只負責數據處理,前端表現方式能夠是任何前端語言(android,ios,html5)
  4. 前端和後端人員更加專一於各自開發,只需接口文檔即可完成先後端交互,無需過多相互瞭解
  5. 服務器性能優化:因爲前端是靜態頁面,經過nginx即可獲取,服務器主要壓力放在了接口上
  6. 輕量,直接基於http,不在須要任何別的諸如消息協議。get/post/put/delete爲CRUD操做
  7. 面向資源,一目瞭然,具備自解釋性。
  8. 數據描述簡單,通常以xml,json作數據交換

27.前端加密

即在數據發送前將數據進行哈希或使用公鑰加密。若是數據被中間人獲取,拿到的則再也不是明文。 固然還有其餘一些優勢:例如避免後端等打印日誌直接暴露明文密碼,還能夠避免明文撞庫等.

缺點:

  1. 密文被hacker獲取之後仍然能夠直接使用密文冒用用戶登陸
  2. 前端加密算法容易被hacker獲取到,使得加密無心義

28.Cookie

使用

瀏覽器會先檢查是否有相應的cookie,有則自動添加在request header中的cookie字段中。這些是瀏覽器自動幫咱們作的,並且每一次http請求瀏覽器都會自動幫咱們作。這個特色很重要,由於這關係到「什麼樣的數據適合存儲在cookie中」。 存儲在cookie中的數據,每次都會被瀏覽器自動放在http請求中,若是這些數據並非每一個請求都須要發給服務端的數據,瀏覽器這設置自動處理無疑增長了網絡開銷;但若是這些數據是每一個請求都須要發給服務端的數據(好比身份認證信息),瀏覽器這設置自動處理就大大免去了重複添加操做。因此對於那種設置「每次請求都要攜帶的信息(最典型的就是身份認證信息)」就特別適合放在cookie中,其餘類型的數據就不適合了。

特徵

不一樣的瀏覽器存放的cookie位置不同,也是不能通用的。 cookie的存儲是以域名形式進行區分的,不一樣的域下存儲的cookie是獨立的。 咱們能夠設置cookie生效的域(當前設置cookie所在域的子域),也就是說,咱們可以操做的cookie是當前域以及當前域下的全部子域 一個域名下存放的cookie的個數是有限制的,不一樣的瀏覽器存放的個數不同,通常爲20個。 每一個cookie存放的內容大小也是有限制的,不一樣的瀏覽器存放大小不同,通常爲4KB。 cookie也能夠設置過時的時間,默認是會話結束的時候,當時間到期自動銷燬。

用途

  1. 會話狀態管理(如用戶登陸狀態、購物車、遊戲分數或其它須要記錄的信息)
  2. 個性化設置(如用戶自定義設置、主題等)
  3. 瀏覽器行爲跟蹤(如跟蹤分析用戶行爲等)

設置選項

  1. expires、max-age來設置cookie的過時時間
  2. domain與path限制cookie能夠被訪問的域與目錄——domain的默認值爲設置該cookie的網頁所在的域名,path默認值爲設置該cookie的網頁所在的目錄。
  3. secure document.cookie = "username=cfangxu; secure" 把cookie設置爲secure,只保證 cookie 與服務器之間的數據傳輸過程加密,而保存在本地的 cookie文件並不加密。就算設置了secure 屬性也並不表明他人不能看到你機器本地保存的 cookie 信息。 機密且敏感的信息毫不應該在 cookie 中存儲或傳輸,由於 cookie 的整個機制本來都是不安全的 注意:若是想在客戶端即網頁中經過 js 去設置secure類型的 cookie,必須保證網頁是https協議的。在http協議的網頁中是沒法設置secure類型cookie的。
  4. httpOnly 在客戶端是不能經過js代碼去設置一個httpOnly類型的cookie的,這種類型的cookie只能經過服務端來設置。 緣由:若是任何 cookie 都能被客戶端經過document.cookie獲取會發生什麼可怕的事情。當咱們的網頁遭受了 XSS 攻擊,有一段惡意的script腳本插到了網頁中。這段script腳本作的事情是:經過document.cookie讀取了用戶身份驗證相關的 cookie,並將這些 cookie 發送到了攻擊者的服務器。攻擊者垂手可得就拿到了用戶身份驗證信息,因而就能夠搖搖大擺地冒充此用戶訪問你的服務器了(由於攻擊者有合法的用戶身份驗證信息,因此會經過你服務器的驗證)。
相關文章
相關標籤/搜索