js隨筆

參考連接:http://www.javashuo.com/article/p-xbazuhvy-cg.html
https://github.com/ly2011/blog/issues/153css

7 ES5/ES6 的繼承除了寫法之外還有什麼區別

class Super {}
class Sub extends Super {}html

const sub = new Sub();vue

Sub.__proto__ === Super;
子類能夠直接經過 proto 尋址到父類。react

function Super() {}
function Sub() {}git

Sub.prototype = new Super();
Sub.prototype.constructor = Sub;es6

var sub = new Sub();github

Sub.__proto__ === Function.prototype;
而經過 ES5 的方式,Sub.__proto__ === Function.prototype算法

相關問題 : js的繼承問題vuex

// 寄生組合式繼承
// 經過借用構造函數來繼承屬性, 經過原型鏈來繼承方法
// 沒必要爲了指定子類型的原型而調用父類型的構造函數,咱們只須要父類型的一個副本而已
// 本質上就是使用寄生式繼承來繼承超類型的原型, 而後再講結果指定給子類型的原型
function object(o){ // ===Object.create()
  function F(){};
  F.prototype = o;
  return new F();
}
function c1(name) {
  this.name = name;
  this.color = ['red', 'green'];
}
c1.prototype.sayName = function () {
  console.log(this.name);
}
function c2(name, age) {
  c1.call(this, name)
  this.age = age
}
// 第一步:建立父類型原型的一個副本
// 第二步:爲建立的副本添加 constructor 屬性, 從而彌補因重寫原型而失去的默認的 constructor 屬性
// 第三步:將新建立的對象(即副本)賦值給子類型的原型
function inheritPrototype(superType, subType) {
  const prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

inheritPrototype(c1, c2);
// c2的方法必須放在寄生繼承以後
c2.prototype.sayAge = function () {
  console.log(this.age);
}

更直接的babel轉義以後的class長什麼樣看看。數據庫

11 將數組扁平化並去除其中重複數據,最終獲得一個升序且不重複的數組

主要是數組的api了

Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})

不用原生的避免不了循環判斷怎麼都浪費性能

12 JS 異步解決方案的發展歷程以及優缺點

一、回調,不夠簡潔,邏輯混亂
二、promise 邏輯清晰 異常捕獲是個問題,只能 reject中捕獲 沒法取消,這是個問題一執行必須有結果。
三、yeild Generator 能夠配合co來使用,特色就是可控制可
四、 async 和await 代碼清晰,缺點 若是多個異步操做沒有依賴性而使用 await 會致使性能上的下降。

await 就是 generator 加上 Promise的語法糖,且內部實現了自動執行 generator

13 Promise 構造函數是同步執行仍是異步執行,那麼 then 方法呢?

構造函數是同步執行的,then方法是異步的,即微任務。及時resolve同步調用。

14 實現一個new

知道原理不用死記硬背
new即實例化一個對象,最終結果是一個構造函數。
目的是該對象得到 示例和原型屬性。實例屬性就是this 指向,原型經過原型來實現。

function new_1 (fn){
    var obj = Object.create(fn.prototype)
    var res = fn.call(obj)
    // 少的這一步在於new 是這樣的構造函數執行以後 若是顯式return 對象 則是該對象,不然就是obj
    return res instanceof fn ? res : obj
}

這裏使用var obj = Object.create(fn.prototype) 而非 var obj = Object.create(fn.prototype)

就是直接使用了Object.create的特性,基於當前對象new一個實例。

function create(obj){
    // 實現了該對象的一個示例
    var fn= function (){}
    fn.prototype = obj
    return new fn()
}

15 http2 多路複用

有個概念就行,同一個http請求,能夠進行多個task,而不用從新創建鏈接
比http1 的keep-alive更優,即原生支持

16 TCP三次握手和四次揮手的理解

TCP 提供一種面向鏈接的、可靠的字節流服務
在一個 TCP 鏈接中,僅有兩方進行彼此通訊。廣播和多播不能用於 TCP
TCP 使用校驗和,確認和重傳機制來保證可靠傳輸
因此每次都須要 校驗 確認 這兩步確認鏈接

三次握手(Three-way Handshake),是指創建一個 TCP 鏈接時,須要客戶端和服務器總共發送3個包。

三次握手的目的是鏈接服務器指定端口,創建 TCP 鏈接,並同步鏈接雙方的序列號和確認號,交換 TCP 窗口大小信息。在 socket 編程中,客戶端執行 connect() 時。將觸發三次握手
45d1b8bb38e06043c9ee5b4e499b1207.jpeg

第一次握手(SYN=1, seq=x):

客戶端發送一個 TCP 的 SYN 標誌位置1的包,指明客戶端打算鏈接的服務器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段裏。

發送完畢後,客戶端進入 SYN_SEND 狀態。

第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):

服務器發回確認包(ACK)應答。即 SYN 標誌位和 ACK 標誌位均爲1。服務器端選擇本身 ISN 序列號,放到 Seq 域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN 加1,即X+1。 發送完畢後,服務器端進入 SYN_RCVD 狀態。

第三次握手(ACK=1,ACKnum=y+1)

客戶端再次發送確認包(ACK),SYN 標誌位爲0,ACK 標誌位爲1,而且把服務器發來 ACK 的序號字段+1,放在肯定字段中發送給對方,而且在數據段放寫ISN的+1

發送完畢後,客戶端進入 ESTABLISHED 狀態,當服務器端接收到這個包時,也進入 ESTABLISHED 狀態,TCP 握手結束。

總結起來就是
一、客戶端攜帶標識位,指明我是誰,要與哪一個端口建鏈接了
二、服務端收到響應,確認客戶端身份,代表本身身份和接收數據能力,返回客戶端
三、客戶端接收以後,確認身份,而且能夠接受,再代表本身能夠接收數據,發給服務端

服務端收到以後,握手結束。

關閉揮手呢就是四次

也叫作改進的三次握手。客戶端或服務器都可主動發起揮手動做,在 socket 編程中,任何一方執行 close() 操做便可產生揮手操做。

第一次揮手(FIN=1,seq=x)

假設客戶端想要關閉鏈接,客戶端發送一個 FIN 標誌位置爲1的包,表示本身已經沒有數據能夠發送了,可是仍然能夠接受數據。

發送完畢後,客戶端進入 FIN_WAIT_1 狀態。

第二次揮手(ACK=1,ACKnum=x+1)

服務器端確認客戶端的 FIN 包,發送一個確認包,代表本身接受到了客戶端關閉鏈接的請求,但尚未準備好關閉鏈接。

發送完畢後,服務器端進入 CLOSE_WAIT 狀態,客戶端接收到這個確認包以後,進入 FIN_WAIT_2 狀態,等待服務器端關閉鏈接。

第三次揮手(FIN=1,seq=y)

服務器端準備好關閉鏈接時,向客戶端發送結束鏈接請求,FIN 置爲1。

發送完畢後,服務器端進入 LAST_ACK 狀態,等待來自客戶端的最後一個ACK。

第四次揮手(ACK=1,ACKnum=y+1)

客戶端接收到來自服務器端的關閉請求,發送一個確認包,並進入 TIME_WAIT狀態,等待可能出現的要求重傳的 ACK 包。

服務器端接收到這個確認包以後,關閉鏈接,進入 CLOSED 狀態。

客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)以後,沒有收到服務器端的 ACK ,認爲服務器端已經正常關閉鏈接,因而本身也關閉鏈接,進入 CLOSED 狀態。

一、第一次客戶端揮手,表示本身要關閉,發出關閉請求
二、服務端收到信息,揮手錶示已知曉,但可能有任務要執行,不能當即結束
三、服務端發出關閉消息,表示進入ready狀態,能夠結束
四、客戶端等待客戶端關閉消息,回覆確認包,我已知曉能夠關閉。 服務端收到以後就關閉。客戶端等待一端時間,確認無消息,則關閉。

1685f09b490fcf6964b4918af780037d.png

概述就是:
三次握手:客戶端發起,目的是鑑權和驗證通信能力
一、客戶端攜帶身份標識,告訴客戶端身份和要創建連接的操做
二、服務端收到以後,一樣返回身份和 標識,帶上本身身份和數傳輸能力
三、客戶端收到服務端鑑權信息和數據,以後確認是對的人和時間。把服務端返回的數據發過去,再證實一下能夠通訊。 雙方進入可通訊狀態,握手結束。

揮手:
一、客戶端 發出斷開請求
二、服務端接受 返回信息標識收到,但還沒結束任務
三、結束當前任務,返回信息,代表進入可結束狀態
四、客戶端收到消息,確認一下,代表服務端能夠關閉,服務端就關閉,客戶端等一會也關閉。

TCP KeepAlive
TCP 的鏈接,其實是一種純軟件層面的概念,在物理層面並無「鏈接」這種概念。TCP 通訊雙方創建交互的鏈接,可是並非一直存在數據交互,有些鏈接會在數據交互完畢後,主動釋放鏈接,而有些不會。在長時間無數據交互的時間段內,交互雙方都有可能出現掉電、死機、異常重啓等各類意外,當這些意外發生以後,這些 TCP 鏈接並將來得及正常釋放,在軟件層面上,鏈接的另外一方並不知道對端的狀況,它會一直維護這個鏈接,長時間的積累會致使很是多的半打開鏈接,形成端系統資源的消耗和浪費,爲了解決這個問題,在傳輸層能夠利用 TCP 的 KeepAlive 機制實現來實現。主流的操做系統基本都在內核裏支持了這個特性。

TCP KeepAlive 的基本原理是,隔一段時間給鏈接對端發送一個探測包,若是收到對方迴應的 ACK,則認爲鏈接仍是存活的,在超過必定重試次數以後仍是沒有收到對方的迴應,則丟棄該 TCP 鏈接。

TCP-Keepalive-HOWTO 有對 TCP KeepAlive 特性的詳細介紹,有興趣的同窗能夠參考。這裏主要說一下,TCP KeepAlive 的侷限。首先 TCP KeepAlive 監測的方式是發送一個 probe 包,會給網絡帶來額外的流量,另外 TCP KeepAlive 只能在內核層級監測鏈接的存活與否,而鏈接的存活不必定表明服務的可用。例如當一個服務器 CPU 進程服務器佔用達到 100%,已經卡死不能響應請求了,此時 TCP KeepAlive 依然會認爲鏈接是存活的。所以 TCP KeepAlive 對於應用層程序的價值是相對較小的。須要作鏈接保活的應用層程序,例如 QQ,每每會在應用層實現本身的心跳功能。

心跳的功能除了這裏還有就是容災降級

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

由於React的合成事件和聲明週期中的行爲都會有事務機制,異步操做state,以便於對於互斥操做的處理,
因此setState會加入隊列中,等待執行。
而原生事件和settimeout等事件,則isBatchingUpdates爲fasle 能夠同步執行

例子就是:

componentDidMount() {
    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 1 次 log 0

    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 2 次 log 0

    setTimeout(() => {
      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  // 第 3 次 log 2

      this.setState({val: this.state.val + 1});## 有如下 3 個判斷數組的方法,請分別介紹它們之間的區別和優劣
      console.log(this.state.val);  // 第 4 次 log 3
    }, 0);
  }

20 介紹下 npm 模塊安裝機制,爲何輸入 npm install 就能夠自動安裝對應的模塊?

參考連接:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/22

21 有如下 3 個判斷數組的方法,請分別介紹它們之間的區別和優劣

Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()

一、toString 兼容性較好
二、 instanceof 的內部機制是經過判斷對象的原型鏈中是否是能找到類型的 prototype

但 instanceof 只能用來判斷對象類型,原始類型不能夠。而且全部對象類型 instanceof Object 都是 true。,若是被修改了就有問題了

三、 Array.isArray 兼容性有問題

instanceof不能檢測來自iframe的數組。就是官方文檔上,window.frames[xx].Array構造出來的數組。

這裏牽扯到安全相關的問題,xss和csrf 攻擊的區別
cookie在於網站會自動獲取 並提交。
csrf 跨站請求僞造這種是攻擊者盜用了當前網站的cookie。

主要發生在正規網站未推出,同時瀏覽其餘網站,致使cookie被利用。其餘網站此時請求正規信息至關於正經常使用戶

一、儘可能使用POST,限制GET
二、將cookie設置爲HttpOnly
三、增長token,脫離cookie額外進行一層驗證
四、 經過Referer識別 來源

參考連接:https://www.jianshu.com/p/67408d73c66d

xss則是利用腳本代碼提交到服務端,再次解析以後進行攻擊,此類爲反射型。

另外一種是存儲性,將腳本落在數據庫中。
例如,張三發了一篇帖子,李四進行回覆:但內容倒是一段js腳本,這篇帖子被他人瀏覽的時候就會中招,例子中的只是一個alert(),但腳本能夠寫的比較複雜一點盜用用戶cookie等等操做。

別人瀏覽時,js腳本能夠獲取當前cookie等信息,發送到目標服務器上。

因此應對就是:
一、入參過濾
二、出參編碼
三、httponly也是有些做用的。
參考連接:http://www.javashuo.com/article/p-utbtyaia-eu.html

http://blog.nsfocus.net/xss-advance/

30 請把兩個數組 ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'] 和 ['A', 'B', 'C', 'D'],合併爲 ['A1', 'A2', 'A', 'B1', 'B2', 'B', 'C1', 'C2', 'C', 'D1', 'D2', 'D']。

function concat(arr1 = [],arr2=[]){
    // 複雜度
    let len2 = arr2.length,
        i=0
    for(i;i<len2;i++){
        let item = arr2[i],
            index = 3*i+2
        arr1.splice(index,0,item)
    } 
    return arr1
}

31 改造下面的代碼,使之輸出0 - 9,寫出你能想到的全部解法

for (var i = 0; i< 10; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000)
}

緣由在於循環結束以後 執行定時器任務,此時變量爲全局做用域,共享,隔離開便可

這個題比較常見了,就是從閉包到let到promise均可以泳道

閉包

for (var i = 0; i < 10; i++) {
    (function(i){
        setTimeout(() => {
            console.log(i);
        }, 1000)
    })(i)
}

let 變量

for (let i = 0; i < 10; i++) {
    setTimeout(() => {
        console.log(i);
    }, 1000)
}

說白了就是不讓公用當前變量,基本類型形參是值傳遞
跟閉包相似

for (var i = 0; i < 10; i++) {
    function run(index){
        setTimeout(() => {
            console.log(index);
        }, 1000)
    }
    run(i)
}

try-catch 有點秀

for(var i = 0; i < 10; i++){ 
  try{
     throw i;
  }catch(i){
     setTimeout(() => { console.log(i); },1000)    
  }
}

32 Virtual DOM 真的比操做原生 DOM 快嗎?談談你的想法

是否快,跟實現算法有關。
在js中 操做dom實際上是瓶頸,虛擬dom是將多個操做操做合併爲一次。

33 下面的代碼打印什麼內容,爲何? C

var b = 10;
(function b(){
    b = 20;
    console.log(b); 
})();

這個是想問變量提高,不過IFF函數 中。 不過函數名是b有點蛋疼了,執行時,向上查找顯然先當前區間應該是function

這個說的有道理

var b = 10;
(function b() {
   // 內部做用域,會先去查找是有已有變量b的聲明,有就直接賦值20,確實有了呀。發現了具名函數 function b(){},拿此b作賦值;
   // IIFE的函數沒法進行賦值(內部機制,相似const定義的常量),因此無效。
  // (這裏說的「內部機制」,想搞清楚,須要去查閱一些資料,弄明白IIFE在JS引擎的工做方式,堆棧存儲IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();

幾個例子:

var b = 10;
(function b() {
   // 內部做用域,會先去查找是有已有變量b的聲明,有就直接賦值20,確實有了呀。發現了具名函數 function b(){},拿此b作賦值;
   // IIFE的函數沒法進行賦值(內部機制,相似const定義的常量),因此無效。
  // (這裏說的「內部機制」,想搞清楚,須要去查閱一些資料,弄明白IIFE在JS引擎的工做方式,堆棧存儲IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();

因此嚴格模式下能看到錯誤:Uncaught TypeError: Assignment to constant variable

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

其餘狀況例子:

有window:

var b = 10;
(function b() {
    window.b = 20; 
    console.log(b); // [Function b]
    console.log(window.b); // 20是必然的
})();

有var:

var b = 10;
(function b() {
    var b = 20; // IIFE內部變量
    console.log(b); // 20
   console.log(window.b); // 10 
})();

34 簡單改造下面的代碼,使之分別打印 10 和 20

var b = 10;
(function b(){
    b = 20;
    console.log(b); 
})();
var b = 10;
(function b(b){
    console.log(b)
    b = 20;
    console.log(b); 
})(b);

35 瀏覽器緩存讀取規則

Service Worker、Memory Cache、Disk Cache 和 Push Cache,那請求的時候 from memory cache 和 from disk cache 的依據是什麼,哪些數據何時存放在 Memory Cache 和 Disk Cache中?

這個仍是有研究的

不易變的css之類from disk hash字符串的js 來自 disk cache

參考這個:https://www.jianshu.com/p/54cc04190252

36 使用迭代的方式實現 flatten 函數。

flatten 函數就是把數組拍平,實現也比較粗暴
判斷元素是否爲數組,是則繼續遍歷。
另外一種比較取巧,轉成字符串,而後再截斷,便可。

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]
// 迭代實現
const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr)
// 遞歸
const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])
// 字符串
arr.join(',').split(',').map(item => Number(item)))

37 爲何 Vuex 的 mutation 和 Redux 的 reducer 中不能作異步操做?

vue用的不是不少,因此不是很清楚mutation裏面爲何不能有異步操做,下面解釋一下爲何Redux的reducer裏不能有異步操做。

先從Redux的設計層面來解釋爲何Reducer必須是純函數
若是你常常用React+Redux開發,那麼就應該瞭解Redux的設計初衷。Redux的設計參考了Flux的模式,做者但願以此來實現時間旅行,保存應用的歷史狀態,實現應用狀態的可預測。因此整個Redux都是函數式編程的範式,要求reducer是純函數也是天然而然的事情,使用純函數才能保證相同的輸入獲得相同的輸入,保證狀態的可預測。因此Redux有三大原則:

單一數據源,也就是state
state 是隻讀,Redux並無暴露出直接修改state的接口,必須經過action來觸發修改
使用純函數來修改state,reducer必須是純函數
下面在從代碼層面來解釋爲何reducer必須是純函數
那麼reducer到底幹了件什麼事,在Redux的源碼中只用了一行來表示:

currentState = currentReducer(currentState, action)
這一行簡單粗暴的在代碼層面解釋了爲何currentReducer必須是純函數。currentReducer就是咱們在createStore中傳入的reducer(至於爲何會加個current有興趣的能夠本身去看源碼),reducer是用來計算state的,因此它的返回值必須是state,也就是咱們整個應用的狀態,而不能是promise之類的。

要在reducer中加入異步的操做,若是你只是單純想執行異步操做,不會等待異步的返回,那麼在reducer中執行的意義是什麼。若是想把異步操做的結果反應在state中,首先整個應用的狀態將變的不可預測,違背Redux的設計原則,其次,此時的currentState將會是promise之類而不是咱們想要的應用狀態,根本是行不通的。

其實這個問題應該是Redux中爲何不能有反作用的操做更合適。

38 下面代碼中 a 在什麼狀況下會打印 1?

var a = ?;
if(a == 1 && a == 2 && a == 3){
    console.log(1);
}

什麼狀況下,這也就用了隱式類型轉換的內容了,
a 要知足下面是三個 == 因此要自定義valueOf了,每次執行一次 value要更新:

var a = {
  val:1,
  valueOf:function(){
    return this.val++
  }
}

另外一種數組:

var a = [1,2,3];
a.join = a.shift;
if(a == 1 && a == 2 && a == 3) {
  console.log('1');
}

es6 Symbol

let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};
if(a == 1 && a == 2 && a == 3) {
  console.log('1');
}

另外還有generate函數
每次執行的結果不一樣:

let a = {
    gn: (function* () {
        yield 1;
        yield 2;
        yield 3;
    })(),
    valueOf() {
        return this.gn.next().value;
    }
};

defineProperty getter

Object.defineProperty(window, 'a', {
    get: function() {
          return this.value = this.value ? (this.value += 1) : 1;
    }
});

總得來講就是在get值的時候 同時執行函數,更新值

39 BFC 及其應用

BFC 塊級格式上線文
BFC 就是塊級格式上下文,是頁面盒模型佈局中的一種 CSS 渲染模式,至關於一個獨立的容器,裏面的元素和外部的元素相互不影響。建立 BFC 的方式有:

html 根元素
float 浮動
絕對定位
overflow 不爲 visiable
display 爲表格佈局或者彈性佈局
BFC 主要的做用是:

清除浮動
防止同一 BFC 容器中的相鄰元素間的外邊距重疊問題

參考連接:https://github.com/glitchboyl/blog/issues/6

40 在 Vue 中,子組件爲什麼不能夠修改父組件傳遞的 Prop

會致使父組件的數據不一致問題,單向數據流向。

41 下面代碼輸出什麼 C

var a = 10;
(function () {
    console.log(a) //undefined
    a = 5
    console.log(window.a) // 10
    var a = 20;
    console.log(a) // 20
})()

想的太複雜,掌握的不是太清楚
這裏就是IIFE 函數做用域是與全局做用域隔離的,
一樣具備變量提高的效果,因此第一和第三輸出就同樣了
二次的輸出,就是外層的a了,不相互影響。

其實做用域和正常的函數沒什麼差異

var a = 10;
function b() {
    console.log(a)
    a = 5
    console.log(window.a)
    var a = 20;
    console.log(a)
}
b()

具名函數也是同樣的輸出

IIFE 參考連接:https://zhuanlan.zhihu.com/p/22465092

IFEE 至關於建立一個匿名函數並執行,當函數被理解成表達式時就會執行,如+(function(){})(),,做用是避免全局污染

42 實現一個 sleep 函數

等待執行,就是延時,promise 、Generator、Async/Await 等方式能夠實現。

43 使用 sort() 對數組 [3, 15, 8, 29, 102, 22] 進行排序,輸出結果

function _sort (arr = []){
    var a = arr.sort && arr.sort((prev,next)=>{
        return prev- next
    })
    console.log(a)
}

44 介紹 HTTPS 握手過程 c https相關內容須要複習

參考 https://developers.weixin.qq.com/community/develop/article/doc/000046a5fdc7802a15f7508b556413
http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
https://zhuanlan.zhihu.com/p/25587986

SSL/TLS協議的基本思路是採用公鑰加密法,也就是說,客戶端先向服務器端索要公鑰,而後用公鑰加密信息,服務器收到密文後,用本身的私鑰解密。
即非對稱加密,但有兩個問題:
一、如何保證公鑰不被篡改?
解決方法:將公鑰放在數字證書中。只要證書是可信的,公鑰就是可信的。

二、公鑰加密計算量太大,如何減小耗用的時間
每一次對話(session),客戶端和服務器端都生成一個"對話密鑰"(session key),用它來加密信息。因爲"對話密鑰"是對稱加密,因此運算速度很是快,而服務器公鑰只用於加密"對話密鑰"自己,這樣就減小了加密運算的消耗時間。

公鑰只是用以握手階段驗證信息。

數字證書用以確認服務端身份

有了證書以後,當你的瀏覽器在訪問某個 HTTPS 網站時,會驗證該站點上的 CA 證書(相似於驗證介紹信的公章)。若是瀏覽器發現該證書沒有問題(證書被某個根證書信任、證書上綁定的域名和該網站的域名一致、證書沒有過時),那麼頁面就直接打開;不然的話,瀏覽器會給出一個警告,告訴你該網站的證書存在某某問題,是否繼續訪問該站點

數字證書有點反過來:用私鑰進行加密,用公鑰進行解密。CA用本身的私鑰對服務端的信息(包含服務端公鑰)進行加密,因爲客戶端無條件信任CA,因此已經提早知道CA的公鑰,當她收到服務端證書的時候,只要用CA的公鑰對Bob證書內容進行解密,發現可否成功解開(還須要校驗完整性)

這就是驗證服務端身份的方式。

"握手階段"涉及四次通訊,咱們一個個來看。須要注意的是,"握手階段"的全部通訊都是明文的。
整個通訊過程能夠歸納爲:
(1) 客戶端向服務器端索要並驗證公鑰。

(2) 雙方協商生成"對話密鑰"。

(3) 雙方採用"對話密鑰"進行加密通訊。

aa1ed965a95a3f490b58e4b126704635.png
一、客戶端發出請求ClientHello
客戶端發出請求,表示要進行加密通訊,即索要服務器的公鑰,內容包括:

  • 支持的協議版本
  • 隨機數,用於生成對話祕鑰
  • 支持的加密方式
    二、服務器迴應(SeverHello)
    針對客戶端的請求,一是返回證書,二是確認加密協議,三是生成隨機數

  • 確認使用的加密通訊協議版本,若是後續不一致則服務器關閉
  • 服務器證書
  • 服務器生成的隨機數,用於生成對話祕鑰
  • 確認使用的加密方法

三、客戶端迴應
收到服務器的證書以後,客戶端先驗證證書,證書合格則取出服務器公鑰,根據該公鑰加密一個隨機數,用於後面生成key,即三個隨機數

如何驗證證書。證書是CA發佈的,去CA驗證便可。

證書裏是服務器的公鑰和身份信息,這些是通過證書頒發機構即CA公證過的,客戶端拿到後去CA驗證,看這個公鑰是否是服務器的,若不是說明證書是僞造的,固然若是證書通過數字簽名證書就不可能被僞造了

  • 一個隨機數(pre-master key)。該隨機數用服務器公鑰加密,防止被竊聽
  • 編碼改變通知,表示隨後的信息都將用雙方商定的加密方法和密鑰發送。
  • 客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的全部內容的hash值,用來供服務器校驗。

pre-master key 用服務器的公鑰加密,能夠防止第三方冒充服務器,由於任何人均可以獲取已經公開的服務器公鑰與客戶段進行通訊。想要得到 pre-master key 明文只有利用服務器的私鑰進行解密,因此這裏進行了服務器的身份驗證,也防止了中間人攻擊。

也就是第三個隨機數是須要服務器用私鑰解密的,因此沒有私鑰,第三方沒法冒充服務端,固然私鑰泄露,那就沒辦法了。

若是須要驗證客戶端身份:
客戶端在發送 pre-master key 以前須要發送客戶端公鑰到服務器,能夠選擇對 pre-master key 用客戶端的私鑰簽名而後再用服務器公鑰加密,則服務器收到 pre-master key 同時對客戶端進行了身份驗證。

四、服務器的最後迴應
服務器收到客戶端的第三個隨機數pre-master key以後,計算生成本次會話所用的"會話密鑰"。而後,向客戶端最後發送下面信息。

  • 編碼改變通知,表示隨後的信息都將用雙方商定的加密方法和密鑰發送
  • 服務器握手結束通知,表示服務器的握手階段已經結束。這一項同時也是前面發送的全部內容的hash值,用來供客戶端校驗。

服務器此時也獲得了三個隨機數,

這裏主要是沒有解釋清楚三個隨機數如何利用起來的,理解下來就是雙方都保存三個隨機數+

hash內容的用處在於確認完整性

單向Hash函數能夠把輸入變成一個定長的輸出串,其特色就是沒法從這個輸出還原回輸入內容,而且不一樣的輸入幾乎不可能產生相同的輸出,即使你要特地去找也很是難找到這樣的輸入(抗碰撞性),
所以客戶端只要將明文內容作一個Hash運算獲得一個Hash值,並一塊兒加密傳遞過去給服務端。
Hacker即使篡改了內容,服務端解密以後發現拿到的內容以及對應計算出來的Hash值與傳遞過來的不一致,說明這個包的完整性被破壞了。

非對稱加密的優點
任何人均可以經過拿到Bob公開的公鑰對內容進行加密,而後只有Bob本身私有的鑰匙才能解密還原出原來內容。
hacker沒法對內容解密,因此第三個隨機數就沒法獲知。

45 HTTPS 握手過程當中,客戶端如何驗證證書的合法性

剛看完就能夠隨手寫一下了,
服務端的數字證書由CA發佈,當服務端返回數據證書時,客戶單可使用CA的公鑰對其進行解密獲得相關內容。內容包括服務器相關的整數時間,公鑰等。

46 對obj push item

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)

本身先猜測,增長了數組的能力,那麼元素應該也被當成不可用對象了,想arguments同樣了。
覺得會保留 34 沒想到是這個:
Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]

push 方法有意具備通用性。該方法和 call() 或 apply() 一塊兒使用時,可應用在相似數組的對象上。push 方法根據 length 屬性來決定從哪裏開始插入給定的值。若是 length 不能被轉成一個數值,則插入的元素索引爲 0,包括 length 不存在時。當 length 不存在時,將會建立它。
惟一的原生類數組(array-like)對象是 Strings,儘管如此,它們並不適用該方法,由於字符串是不可改變的。

這裏length爲2,因此從第三位開始插入,此時2,3對應的value 就被替換掉了。

47 雙向綁定和 vuex 是否衝突

不發表評論暫時

48 call和apply的差異,性能 c

區別在於參數傳遞形式,call爲參數,apply爲數組。
下意識仍是 apply更好一些。
也對實際上call就是函數調用的常規形式,apply還要轉化一下。

看結論呢:
早期call確實比apply快那麼一丟丟,可是如今二者沒什麼差距,即便有也微乎其微。

49 爲何一般在發送數據埋點請求的時候使用的是 1x1 像素的透明 gif 圖片?

這個沒注意過,不過仍是體積小、兼容性好
1 1 體積小和性能
gif的體積顯然不如png,透明是減小重繪嗎?

一、使用圖片是支持跨域
二、圖片請求無阻塞
三、GIF的最低合法體積最小(最小的BMP文件須要74個字節,PNG須要67個字節,而合法的GIF,只須要43個字節)
無需相應
目前比較合適的作法是服務器發送"204 No Content",即「服務器成功處理了請求,但不須要返回任何實體內容」。

50 (百度)實現 (5).add(3).minus(2) 功能。

這是調用鏈的實現
5 + 3 - 2,結果爲 6
原來這個用法沒看明白: (5) 等於直接使用 5 其實
那就是Number原型鏈加方法

Number.prototype.add=function(num){
    return this.valueOf() + num
}
Number.prototype.minus=function(num){
    return this.valueOf()- num
}
相關文章
相關標籤/搜索