web前端面試總結(自認為還算全面哈哈哈哈哈!!!!)

張張-?發表於2019-10-23

一、CSS問題

1.flex佈局

display:flex; 在父元素設定,子元素受彈性盒影響,預設排成一行,如果超出一行,按比例壓縮 flex:1; 子元素設定,設定子元素如何分配父元素的空間,flex:1,子元素寬度佔滿整個父元素align-items:center 定義子元素在父容器中的對齊方式,center 垂直居中justify-content:center 設定子元素在父元素中居中,前提是子元素沒有把父元素佔滿,讓子元素水平居中。

2.css3的新特性

transtion transition-property 規定設定過渡效果的 CSS 屬性的名稱。

transition-duration 規定完成過渡效果需要多少秒或毫秒。

transition-timing-function 規定速度效果的速度曲線。

transition-delay 定義過渡效果何時開始。

animation屬性可以像Flash製作動畫一樣,通過控制關鍵幀來控制動畫的每一步,實現更為複雜的動畫效果。

ainimation實現動畫效果主要由兩部分組成:

通過類似Flash動畫中的幀來宣告一個動畫;

在animation屬性中呼叫關鍵幀宣告的動畫。

translate 3D建模效果

3.img中alt和title的區別

圖片中的 alt屬性是在圖片不能正常顯示時出現的文字提示。alt有利於SEO優化

圖片中的 title屬性是在滑鼠在移動到元素上的文字提示。

4.用純CSS建立一個三角形

 <style>
    div {
        width: 0;
        height: 0;
        border-top: 40px solid transparent;
        border-left: 40px solid transparent;
        border-right: 40px solid transparent;
        border-bottom: 40px solid #ff0000;
    }
    </style>
</head>
<body>
  <div></div>
</body>
複製程式碼

5.如何理解CSS的盒子模型?

標準盒子模型:寬度=內容的寬度(content)+ border + padding

低版本IE盒子模型:寬度=內容寬度(content+border+padding)

6.如何讓一個div水平居中

已知寬度,block元素 ,新增新增margin:0 auto屬性。

已知寬度,絕對定位的居中 ,上下左右都為0,margin:auto

7.如何讓一個div水平垂直居中

div {
position: relative / fixed; /* 相對定位或絕對定位均可 */
width:500px;
height:300px;
top: 50%;
left: 50%;
margin-top:-150px;
margin-left:-250px;
 外邊距為自身寬高的一半 */
background-color: pink; /* 方便看效果 */
 }

.container {
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
 
}
.container div {
width: 100px; /* 可省 */
height: 100px; /* 可省 */
background-color: pink; /* 方便看效果 */
}  
複製程式碼

8.如何清除浮動?

clear清除浮動(新增空div法)在浮動元素下方新增空div,並給該元素寫css樣式 {clear:both;height:0;overflow:hidden;}

給浮動元素父級設定高度

父級同時浮動(需要給父級同級元素新增浮動)

父級設定成inline-block,其margin: 0 auto居中方式失效

給父級新增overflow:hidden 清除浮動方法

萬能清除法 after偽類 清浮動(現在主流方法,推薦使用)

float_div:after{
content:".";
clear:both;
display:block;
height:0;
overflow:hidden;
visibility:hidden;
}
.float_div{
zoom:1
}
複製程式碼

9.css3實現三欄佈局,左右固定,中間自適應

聖盃佈局/雙飛翼佈局

 <style>
        * {
            margin: 0;
            padding: 0;
        }
        .middle,
        .left,
        .right {
            position: relative;
            float: left;
            min-height: 130px;
        }
        .container {
            padding: 0 220px 0 200px;
            overflow: hidden;
        }
        .left {
            margin-left: -100%;
            left: -200px;
            width: 200px;
            background: red;
        }
        .right {
            margin-left: -220px;
            right: -220px;
            width: 220px;
            background: green;
        }
        .middle {
            width: 100%;
            background: blue;
            word-break: break-all;
        }
    </style>
</head>
<body>
    <div class='container'>
        <div class='middle'></div>
        <div class='left'></div>
        <div class='right'></div>
    </div>
</body>
複製程式碼

10.display:none 和 visibility: hidden的區別

display:none 隱藏對應的元素,在文件佈局中不再給它分配空間,它各邊的元素會合攏,就當他從來不存在。

visibility:hidden 隱藏對應的元素,但是在文件佈局中仍保留原來的空間。

11.CSS中 link 和@import 的區別是?

link屬於HTML標籤,而@import是CSS提供的頁面被載入的時,link會同時被載入,而@import引用的CSS會等到頁面被載入完再載入

import只在IE5以上才能識別,而link是HTML標籤,無相容問題

link方式的樣式的權重 高於@import的權重.

12.position的absolute與fixed共同點與不同點

共同點: 改變行內元素的呈現方式,display被置為block 讓元素脫離普通流,不佔據空間 預設會覆蓋到非定位元素上

不同點: absolute的”根元素“是可以設定的 fixed的”根元素“固定為瀏覽器視窗。當你滾動網頁,fixed元素與瀏覽器視窗之間的距離是不變的。

13..transition和animation的區別

Animation和transition大部分屬性是相同的,他們都是隨時間改變元素的屬性值,他們的主要區別是transition需要觸發一個事件才能改變屬性, 而animation不需要觸發任何事件的情況下才會隨時間改變屬性值,並且transition為2幀,從from .... to,而animation可以一幀一幀的。

transition 規定動畫的名字 規定完成過渡效果需要多少秒或毫秒 規定速度效果 定義過渡效果何時開始 animation 指定要繫結到選擇器的關鍵幀的名稱

14.CSS優先順序

不同級別:總結排序:!important > 行內樣式>ID選擇器 > 類選擇器 > 標籤 > 萬用字元 > 繼承 > 瀏覽器預設屬性
	1.屬性後面加!import 會覆蓋頁面內任何位置定義的元素樣式
	2.作為style屬性寫在元素內的樣式
	3.id選擇器
	4.類選擇器
	5.標籤選擇器
	6.萬用字元選擇器(*)
	7.瀏覽器自定義或繼承
**同一級別:後寫的會覆蓋先寫的**
複製程式碼

css選擇器的解析原則:選擇器定位DOM元素是從右往左的方向,這樣可以儘早的過濾掉一些不必要的樣式規則和元素

15.雪碧圖:

        多個圖片整合在一個圖片中的圖
	使用雪碧圖可以減少網路請求的次數,加快允許的速度
	通過background-position,去定點陣圖片在螢幕的哪個位置
複製程式碼

二、JS問題

1.typeof和instance of 檢測資料型別有什麼區別?

相同點: 都常用來判斷一個變數是否為空,或者是什麼型別的。

不同點: typeof 返回值是一個字串,用來說明變數的資料型別 instanceof 用於判斷一個變數是否屬於某個物件的例項.

16.使元素消失的方法

visibility:hidden、display:none、z-index=-1、opacity:0
1.opacity:0,該元素隱藏起來了,但不會改變頁面佈局,並且,如果該元素已經繫結了一些事件,如click事件也能觸發
2.visibility:hidden,該元素隱藏起來了,但不會改變頁面佈局,但是不會觸發該元素已經繫結的事件
3.display:node, 把元素隱藏起來,並且會改變頁面佈局,可以理解成在頁面中把該元素刪掉
複製程式碼

.談一談深克隆和淺克隆?

淺克隆: 只是拷貝了基本型別的資料,而引用型別資料,複製後也是會發生引用,我們把這種拷貝叫做“(淺複製)淺拷貝”,換句話說,淺複製僅僅是指向被複制的記憶體地址,如果原地址中物件被改變了,那麼淺複製出來的物件也會相應改變。

深克隆: 建立一個新物件,屬性中引用的其他物件也會被克隆,不再指向原有物件地址。 JSON.parse、JSON.stringify()

3.es6的新特性都有哪些?

let定義塊級作用域變數 沒有變數的提升,必須先宣告後使用 let宣告的變數,不能與前面的let,var,conset宣告的變數重名

const 定義只讀變數 const宣告變數的同時必須賦值,const宣告的變數必須初始化,一旦初始化完畢就不允許修改 const宣告變數也是一個塊級作用域變數 const宣告的變數沒有“變數的提升”,必須先宣告後使用 const宣告的變數不能與前面的let, var , const宣告的變數重 const定義的物件\陣列中的屬性值可以修改,基礎資料型別不可以

ES6可以給形參函式設定預設值

在陣列之前加上三個點(...)展開運算子

陣列的解構賦值、物件的解構賦值

箭頭函式的特點 箭頭函式相當於匿名函式,是不能作為建構函式的,不能被new 箭頭函式沒有arguments實參集合,取而代之用...剩餘運算子解決 箭頭函式沒有自己的this。他的this是繼承當前上下文中的this 箭頭函式沒有函式原型 箭頭函式不能當做Generator函式,不能使用yield關鍵字 不能使用call、apply、bind改變箭頭函式中this指向 Set資料結構,陣列去重

4.==和===區別是什麼?

=賦值

==返回一個布林值;相等返回true,不相等返回false; 允許不同資料型別之間的比較; 如果是不同型別的資料進行,會預設進行資料型別之間的轉換; 如果是物件資料型別的比較,比較的是空間地址

=== 只要資料型別不一樣,就返回false;

5.常見的設計模式有哪些?

1、js工廠模式
2、js建構函式模式
3、js原型模式
4、建構函式+原型的js混合模式
5、建構函式+原型的動態原型模式
6、觀察者模式
7、釋出訂閱模式
複製程式碼

6.call bind apply 的區別?

call() 和apply()的第一個引數相同,就是指定的物件。這個物件就是該函式的執行上下文。

call()和apply()的區別就在於,兩者之間的引數。

call()在第一個引數之後的 後續所有引數就是傳入該函式的值。

apply() 只有兩個引數,第一個是物件,第二個是陣列,這個陣列就是該函式的引數。 bind() 方法和前兩者不同在於: bind() 方法會返回執行上下文被改變的函式而不會立即執行,而前兩者是 直接執行該函式。他的引數和call()相同。

7.js繼承方式有哪些?

原型鏈繼承 核心: 將父類的例項作為子類的原型

構造繼承 核心:使用父類的建構函式來增強子類例項,等於是複製父類的例項屬性給子類

例項繼承 核心:為父類例項新增新特性,作為子類例項返回

拷貝繼承

組合繼承 核心:通過呼叫父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現 函式複用

寄生組合繼承 核心:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造的時候,就不會初始化兩次實 例方法/屬性,避免的組合繼承的缺點

8.你怎樣看待閉包?

個人感覺,簡單來說閉包就是在函式裡面宣告函式,本質上說就是在函式內部和函式外部搭建起一座橋樑,使得子函式可以訪問父函式中所有的區域性變數,但是反之不可以,這只是閉包的作用之一,另一個作用,則是保護變數不受外界汙染,使其一直存在記憶體中,在工作中我們還是少使用閉包的好,因為閉包太消耗記憶體,不到萬不得已的時候儘量不使用。

9.你是如何理解原型和原型鏈的?

把所有的物件共用的屬性全部放在堆記憶體的一個物件(共用屬性組成的物件),然後讓每一個物件的 __proto__儲存這個「共用屬性組成的物件」的地址。而這個共用屬性就是原型,原型出現的目的就是為了減少不必要的記憶體消耗。而原型鏈就是物件通過__proto__向當前例項所屬類的原型上查詢屬性或方法的機制,如果找到Object的原型上還是沒有找到想要的屬性或者是方法則查詢結束,最終會返回undefined

10.瀏覽器渲染的主要流程是什麼?

將html程式碼按照深度優先遍歷來生成DOM樹。 css檔案下載完後也會進行渲染,生成相應的CSSOM。 當所有的css檔案下載完且所有的CSSOM構建結束後,就會和DOM一起生成Render Tree。 接下來,瀏覽器就會進入Layout環節,將所有的節點位置計算出來。 最後,通過Painting環節將所有的節點內容呈現到螢幕上。

11.從輸入url地址到頁面相應都發生了什麼?

1、瀏覽器的位址列輸入URL並按下回車。
2、瀏覽器查詢當前URL是否存在快取,並比較快取是否過期。3、DNS解析URL對應的IP。
4、根據IP建立TCP連線(三次握手)。
5、HTTP發起請求。
6、伺服器處理請求,瀏覽器接收HTTP響應。
7、渲染頁面,構建DOM樹。
8、關閉TCP連線(四次揮手)
複製程式碼

12.session、cookie、localStorage的區別

相同點 都是儲存在瀏覽器端,且同源的。

不同點

  • cookie資料始終在同源的http請求中攜帶,即cookie在瀏覽器和伺服器間來回傳遞。
  • 而sessionStorage和localStorage不會自動把資料發給伺服器,僅在本地儲存。
  • cookie資料還有路徑(path)的概念,可以限制cookie只屬於某個路徑下。 儲存大小限制也不同,cookie資料不能超過4k,同時因為每次http請求都會攜帶cookie,所以cookie只適合儲存很小的資料。
  • sessionStorage和localStorage 雖然也有儲存大小的限制,但比cookie大得多,可以達到5M或更大。 資料有效期不同,sessionStorage:僅在當前瀏覽器視窗關閉前有效,自然也就不可能持久保持;
  • localStorage:始終有效,視窗或瀏覽器關閉也一直儲存,因此用作持久資料;
  • cookie只在設定的cookie過期時間之前一直有效,即使視窗或瀏覽器關閉。 作用域不同,sessionStorage不在不同的瀏覽器視窗中共享,即使是同一個頁面;
  • localStorage 在所有同源視窗中都是共享的;cookie也是在所有同源視窗中都是共享的。

13.js中跨域方法

同源策略(協議+埠號+域名要相同)

1、jsonp跨域(只能解決get) 原理:動態建立一個script標籤。利用script標籤的src屬性不受同源策略限制,因為所有的src屬性和href屬性都不受同源策略的限制,可以請求第三方伺服器資源內容

步驟: 1).去建立一個script標籤 2).script的src屬性設定介面地址 3).介面引數,必須要帶一個自定義函式名,要不然後臺無法返回資料 4).通過定義函式名去接受返回的資料

2、document.domain 基礎域名相同 子域名不同

3、window.name 利用在一個瀏覽器視窗內,載入所有的域名都是共享一個window.name

4、伺服器設定對CORS的支援 原理:伺服器設定Access-Control-Allow-Origin HTTP響應頭之後,瀏覽器將會允許跨域請求

5、利用h5新特性window.postMessage()

14.前端有哪些頁面優化方法?

  • 減少 HTTP請求數
  • 從設計實現層面簡化頁面
  • 合理設定 HTTP快取
  • 資源合併與壓縮
  • 合併 CSS圖片,減少請求數的又一個好辦法。
  • 將外部指令碼置底(將指令碼內容在頁面資訊內容載入後再載入)
  • 多圖片網頁使用圖片懶載入。
  • 在js中儘量減少閉包的使用
  • 儘量合併css和js檔案
  • 儘量使用字型圖示或者SVG圖示,來代替傳統的PNG等格式的圖片
  • 減少對DOM的操作
  • 在JS中避免“巢狀迴圈”和 “死迴圈”
  • 儘可能使用事件委託(事件代理)來處理事件繫結的操作

15.Ajax的四個步驟

1.建立ajax例項

2.執行open 確定要訪問的連結 以及同步非同步

3.監聽請求狀態

4.傳送請求

16.陣列去重的方法

ES6的set物件 先將原陣列排序,在與相鄰的進行比較,如果不同則存入新陣列

function unique(arr){
    var arr2 = arr.sort();
    var res = [arr2[0]];
    for(var i=1;i<arr2.length;i++){
        if(arr2[i] !== res[res.length-1]){
        res.push(arr2[i]);
    }
}
return res;
}
利用下標查詢
 function unique(arr){
    var newArr = [arr[0]];
    for(var i=1;i<arr.length;i++){
        if(newArr.indexOf(arr[i]) == -1){
        newArr.push(arr[i]);
    }
}
return newArr;
}
複製程式碼

17.ajax中get和post請求的區別

  • get 一般用於獲取資料
  • get請求如果需要傳遞引數,那麼會預設將引數拼接到url的後面;然後傳送給伺服器;
  • get請求傳遞引數大小是有限制的;是瀏覽器的位址列有大小限制;
  • get安全性較低
  • get 一般會走快取,為了防止走快取,給url後面每次拼的引數不同;放在?後面,一般用個時間戳
  • post 一般用於傳送資料
  • post傳遞引數,需要把引數放進請求體中,傳送給伺服器;
  • post請求引數放進了請求體中,對大小沒有要求;
  • post安全性比較高;
  • post請求不會走快取;

18.ajax的狀態碼

2開頭

  • 200 : 代表請求成功;

3開頭

  • 301 : 永久重定向;
  • 302: 臨時轉移
  • 304 : 讀取快取 [表示瀏覽器端有快取,並且服務端未更新,不再向服務端請求資源]
  • 307:臨時重定向

以4開頭的都是客戶端的問題;

  • 400 :資料/格式錯誤
  • 401: 許可權不夠;(身份不合格,訪問網站的時候,登入和不登入是不一樣的)
  • 404 : 路徑錯誤,找不到檔案

以5開頭都是服務端的問題

  • 500 : 伺服器的問題
  • 503: 超負荷;

19.移動端的相容問題

  • 給移動端新增點選事件會有300S的延遲 如果用點選事件,需要引一個fastclick.js檔案,解決300s的延遲 一般在移動端用ontouchstart、ontouchmove、ontouchend
  • 移動端點透問題,touchstart 早於 touchend 早於click,click的觸發是有延遲的,這個時間大概在300ms左右,也就是說我們tap觸發之後蒙層隱藏, 此時 click還沒有觸發,300ms之後由於蒙層隱藏,我們的click觸發到了下面的a連結上 儘量都使用touch事件來替換click事件。例如用touchend事件(推薦)。 用fastclick,github.com/ftlabs/fast… 用preventDefault阻止a標籤的click 消除 IE10 裡面的那個叉號 input:-ms-clear{display:none;}
  • 設定快取 手機頁面通常在第一次載入後會進行快取,然後每次重新整理會使用快取而不是去重新向伺服器傳送請求。如果不希望使用快取可以設定no-cache。
  • 圓角BUG 某些Android手機圓角失效 background-clip: padding-box; 防止手機中網頁放大和縮小 這點是最基本的,做為手機網站開發者來說應該都知道的,就是設定meta中的viewport
  • 設定使用者截止縮放,一般寫視口的時候就已經寫好了。

20.JS中同步和非同步,以及js的事件流

同步:在同一時間內做一件事情

非同步:在同一時間內做多個事情 JS是單執行緒的,每次只能做一件事情,JS執行在瀏覽器中,瀏覽器是多執行緒的,可以在同一時間執行多個任務。

21.JS中常見的非同步任務

定時器、ajax、事件繫結、回撥函式、async await、promise

22.TCP的三次握手和四次揮手

三次握手

  • 第一次握手:客戶端傳送一個SYN碼給伺服器,要求建立資料連線;
  • 第二次握手: 伺服器SYN和自己處理一個SYN(標誌);叫SYN+ACK(確認包);傳送給客戶端,可以建立連線
  • 第三次握手: 客戶端再次傳送ACK向伺服器,伺服器驗證ACK沒有問題,則建立起連線;

四次揮手

  • 第一次揮手: 客戶端傳送FIN(結束)報文,通知伺服器資料已經傳輸完畢;
  • 第二次揮手: 伺服器接收到之後,通知客戶端我收到了SYN,傳送ACK(確認)給客戶端,資料還沒有傳輸完成
  • 第三次揮手: 伺服器已經傳輸完畢,再次傳送FIN通知客戶端,資料已經傳輸完畢
  • 第四次揮手: 客戶端再次傳送ACK,進入TIME_WAIT狀態;伺服器和客戶端關閉連線;

23.為什麼建立連線是三次握手,而斷開連線是四次揮手呢?

建立連線的時候, 伺服器在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。 而關閉連線時,伺服器收到對方的FIN報文時,僅僅表示對方不再傳送資料了但是還能接收資料,而自己也未必全部資料都傳送給對方了,所以己方可以立即關閉,也可以傳送一些資料給對方後,再傳送FIN報文給對方來表示同意現在關閉連線,因此,己方ACK和FIN一般都會分開傳送,從而導致多了一次。

24.DOM diff原理

  • 如果元素型別發生變化,直接替換
  • 如果是文字,則比較文字里面的內容,是否有差異,如果是元素就需要比較當前元素的屬性是否相等,會先比較key, 在比較型別 為什麼 react中迴圈 建議不要使用索引 ,如果純為了展示 那可以使用索引

25.作用域

全域性作用域

  • 瀏覽器開啟一個頁面時,瀏覽器會給JS程式碼提供一個全域性的執行環境,那麼這個環境就是全域性作用域 一個頁面只有一個全域性作用域,全域性作用域下有一個window物件 window是全域性作用域下的最大的一個內建物件(全域性作用域下定義的變數和函式都會儲存在window下) 如果是全域性變數,都會給window新增一個鍵值對;屬性名就是變數名,屬性值就是變數所儲存的值 如果變數只被var過,那麼儲存值是undefined 在私有作用域中是可以獲取到全域性變數的,但是在全域性作用域中不能獲取私有變數

私有作用域

  • 函式執行會形成一個新的私有的作用域(執行多次,形成多個私有作用域) 私有作用域在全域性作用域中形成,具有包含的關係; 在一個全域性作用域中,可以有很多個私有作用域 在私有作用域下定義的變數都是私有變數 形參也是私有變數 函式體中通過function定義的函式也是私有的,在全域性作用域不能使用;

塊級作用域

  • es6中新引入的一種作用域 在js中常見到的if{}、for{}、while{}、try{}、catch{}、switch case{}都是塊級作用域 var obj = {} //物件的大括號不是塊級作用域 塊級作用域中的同一變數不能被重複宣告(塊級下var和function不能重名,否則會報錯) 作用域鏈

上級作用域

  • 函式在哪裡定義,他的上一級作用域就是哪,和函式在哪個作用域下執行沒有關係 作用域鏈:當獲取變數所對應的值時,首先看變數是否是私有變數,如果不是私有變數,要繼續向上一級作用域中查詢,如果上一級也沒有,那麼會繼續向上一級查詢,直到找到全域性作用域為止;如果全域性作用域也沒有,則會報錯;這樣一級一級向上查詢,就會形成作用域鏈 當前作用域沒有的,則會繼續向上一級作用域查詢 當前函式的上一級作用域跟函式在哪個作用域下執行沒有關係,只跟函式在哪定義有關(重點)

26.Promise處理非同步

他是ES6中新增加的一個類(new Promise),目的是為了管理JS中的非同步程式設計的,所以把他稱為“Promise設計模式” new Promise 經歷三個狀態:padding(準備狀態:初始化成功、開始執行非同步的任務)、fullfilled(成功狀態)、rejected(失敗狀態)== Promise本身是同步程式設計的,他可以管理非同步操作的(重點),new Promise的時候,會把傳遞的函式立即執行 Promise函式天生有兩個引數,resolve(當非同步操作執行成功,執行resolve方法),rejected(當非同步操作失敗,執行reject方法) then()方法中有兩個函式,第一個傳遞的函式是resolve,第二個傳遞的函式是reject ajax中false代表同步,true代表非同步,如果使用非同步,不等ajax徹底完成

27.map和forEach的區別

相同點

  • 都是迴圈遍歷陣列中的每一項 forEach和map方法裡每次執行匿名函式都支援3個引數,引數分別是item(當前每一項)、index(索引值)、arr(原陣列),需要用哪個的時候就寫哪個 匿名函式中的this都是指向window 只能遍歷陣列

不同點

  • map方法返回一個新的陣列,陣列中的元素為原始陣列呼叫函式處理後的值。(原陣列進行處理之後對應的一個新的陣列。) map()方法不會改變原始陣列 map()方法不會對空陣列進行檢測 forEach()方法用於呼叫陣列的每個元素,將元素傳給回撥函式.(沒有return,返回值是undefined)

注意:forEach對於空陣列是不會呼叫回撥函式的。

28.async await函式

async/await函式是非同步程式碼的新方式

async/await是基於promise實現的

async/await使非同步程式碼更像同步程式碼

await 只能在async函式中使用,不能再普通函式中使用,要成對出現

預設返回一個promise例項,不能被改變

await下面的程式碼是非同步,後面的程式碼是同步的

29.this指向

  • 全域性作用域下的this指向window
  • 如果給元素的事件行為繫結函式,那麼函式中的this指向當前被繫結的那個元素
  • 函式中的this,要看函式執行前有沒有 . , 有 . 的話,點前面是誰,this就指向誰,如果沒有點,指向window
  • 自執行函式中的this永遠指向window
  • 定時器中函式的this指向window
  • 建構函式中的this指向當前的例項
  • call、apply、bind可以改變函式的this指向
  • 箭頭函式中沒有this,如果輸出this,就會輸出箭頭函式定義時所在的作用域中的this

30.原型

所有的函式資料型別都天生自帶一個prototype屬性,該屬性的屬性值是一個物件 prototype的屬性值中天生自帶一個constructor屬性,其constructor屬性值指向當前原型所屬的類 所有的物件資料型別,都天生自帶一個_proto_屬性,該屬性的屬性值指向當前例項所屬類的原型

31.非同步回撥(如何解決回撥地獄)

promise、generator、async/await

promise: 1.是一個物件,用來傳遞非同步操作的資訊。代表著某個未來才會知道結果的時間,並未這個事件提供統一的api,供進非同步處理
	  2.有了這個物件,就可以讓非同步操作以同步的操作的流程來表達出來,避免層層巢狀的回撥地獄
	  3.promise代表一個非同步狀態,有三個狀態pending(進行中),Resolve(以完成),Reject(失敗)
	  4.一旦狀態改變,就不會在變。任何時候都可以得到結果。從進行中變為以完成或者失敗
		promise.all() 裡面狀態都改變,那就會輸出,得到一個陣列
		promise.race() 裡面只有一個狀態變為rejected或者fulfilled即輸出
		promis.finally()不管指定不管Promise物件最後狀態如何,都會執行的操作(本質上還是then方法的特例)
複製程式碼

32.前端事件流

事件流描述的是從頁面中接受事件的順序,事件 捕獲階段 處於目標階段 事件冒泡階段 addeventListener 最後這個布林值引數如果是true,表示在捕獲階段呼叫事件處理程式;如果是false,表示在冒泡階段呼叫事件處理程式。
  1、事件捕獲階段:實際目標div在捕獲階段不會接受事件,也就是在捕獲階段,事件從document到<html>再到<body>就停止了。
      2、處於目標階段:事件在div發生並處理,但是事件處理會被看成是冒泡階段的一部分。
      3、冒泡階段:事件又傳播迴文件
   阻止冒泡事件event.stopPropagation()
	  function stopBubble(e) {
    		if (e && e.stopPropagation) { // 如果提供了事件物件event 這說明不是IE瀏覽器
      		e.stopPropagation()
    		} else {
      		window.event.cancelBubble = true //IE方式阻止冒泡
    	      }
  		   }
   阻止預設行為event.preventDefault()
 function stopDefault(e) {
    if (e && e.preventDefault) {
      e.preventDefault()
    } else {
      // IE瀏覽器阻止函式器預設動作的行為
      window.event.returnValue = false
    }
  }
複製程式碼

33.事件如何先捕獲後冒泡?

在DOM標準事件模型中,是先捕獲後冒泡。但是如果要實現先冒泡後捕獲的效果, 對於同一個事件,監聽捕獲和冒泡,分別對應相應的處理函式,監聽到捕獲事件,先暫緩執行,直到冒泡事件被捕獲後再執行捕獲事件。

  • 哪些事件不支援冒泡事件:滑鼠事件:mouserleave mouseenter 焦點事件:blur focus UI事件:scroll resize

34. 如何判斷一個變數是物件還是陣列(prototype.toString.call())。

千萬不要使用typeof來判斷物件和陣列,因為這種型別都會返回object。
複製程式碼

typeOf()是判斷基本型別的Boolean,Number,symbol, undefined, String。 對於引用型別:除function,都返回object null返回object。

installOf() 用來判斷A是否是B的例項,installof檢查的是原型。

toString() 是Object的原型方法,對於 Object 物件,直接呼叫 toString() 就能返回 [Object Object] 。而對於其他物件,則需要通過 call / apply 來呼叫才能返回正確的型別資訊。

hasOwnProperty()方法返回一個布林值,指示物件自身屬性中是否具有指定的屬性,該方法會忽略掉那些從原型鏈上繼承到的屬性。

isProperty()方法測試一個物件是否存在另一個物件的原型鏈上。

35.setTimeout 和 setInterval的機制

因為js是單執行緒的。瀏覽器遇到etTimeout 和 setInterval會先執行完當前的程式碼塊,在此之前會把定時器推入瀏覽器的
待執行時間佇列裡面,等到瀏覽器執行完當前程式碼之後會看下事件佇列裡有沒有任務,有的話才執行定時器裡的程式碼
複製程式碼

36.splice和slice、map和forEach、 filter()、reduce()的區別

 1.slice(start,end):方法可以從已有陣列中返回選定的元素,返回一個新陣列,
 包含從start到end(不包含該元素)的陣列方法
	注意:該方法不會更新原陣列,而是返回一個子陣列
 2.splice():該方法想或者從陣列中新增或刪除專案,返回被刪除的專案。(該方法會改變原陣列)
	splice(index, howmany,item1,...itemx)
		·index引數:必須,整數規定新增或刪除的位置,使用負數,從陣列尾部規定位置
		·howmany引數:必須,要刪除的數量,
		·item1..itemx:可選,向陣列新增新專案
3.map():會返回一個全新的陣列。使用於改變資料值的時候。會分配記憶體儲存空間陣列並返回,forEach()不會返回資料
4.forEach(): 不會返回任何有價值的東西,並且不打算改變資料,單純的只是想用資料做一些事情,他允許callback更改原始陣列的元素
5.reduce(): 方法接收一個函式作為累加器,陣列中的每一個值(從左到右)開始縮減,最終計算一個值,不會改變原陣列的值
6.filter(): 方法建立一個新陣列,新陣列中的元素是通過檢查指定陣列中符合條件的所有元素。它裡面通過function去做處理	
複製程式碼

VUE問題

1.聊聊對vue的理解

vue是一個漸進式的JS框架。他易用,靈活,高效; 可以把一個頁面分隔成多個元件;當其他頁面有類似功能時,直接讓封裝的元件進行復用; 他是構建使用者介面的宣告式框架,只關心圖層;不關心具體是如何實現的

2.V-model的原理是什麼?

Vue的雙向資料繫結是由資料劫持結合釋出者訂閱者實現的。 資料劫持是通過Object.defineProperty()來劫持物件資料的setter和getter操作。 在資料變動時作你想做的事

  • 原理 通過Observer來監聽自己的model資料變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通訊橋樑,達到資料變化->檢視更新 在初始化vue例項時,遍歷data這個物件,給每一個鍵值對利用Object.definedProperty對data的鍵值對新增get和set方法,利用了事件監聽DOM的機制,讓檢視去改變資料

3.談談對生命週期的理解

  • beforeCreate階段:vue例項的掛載元素el和資料物件data都是undefined,還沒有初始化。
  • created階段:vue例項的資料物件data有了,可以訪問裡面的資料和方法,未掛載到DOM,el還沒有
  • beforeMount階段:vue例項的el和data都初始化了,但是掛載之前為虛擬的dom節點
  • mounted階段:vue例項掛載到真實DOM上,就可以通過DOM獲取DOM節點
  • beforeUpdate階段:響應式資料更新時呼叫,發生在虛擬DOM打補丁之前,適合在更新之前訪問現有的DOM,比如手動移除已新增的事件監聽器
  • updated階段:虛擬DOM重新渲染和打補丁之後呼叫,組成新的DOM已經更新,避免在這個鉤子函式中運算元據,防止死迴圈
  • beforeDestroy階段:例項銷燬前呼叫,例項還可以用,this能獲取到例項,常用於銷燬定時器,解綁事件
  • destroyed階段:例項銷燬後呼叫,呼叫後所有事件監聽器會被移除,所有的子例項都會被銷燬

4.VUE和REACT有什麼區別?

react整體是函式式的思想,把元件設計成純元件,狀態和邏輯通過引數傳入,所以在react中,是單向資料流;

vue的思想是響應式的,也就是基於是資料可變的,通過對每一個屬性建立Watcher來監聽,當屬性變化的時候,響應式的更新對應的虛擬dom。

5.vuex的流程

頁面通過mapAction非同步提交事件到action。action通過commit把對應引數同步提交到mutation。
mutation會修改state中對於的值。 最後通過getter把對應值跑出去,在頁面的計算屬性中
通過mapGetter來動態獲取state中的值
複製程式碼

6.vuex有哪幾種狀態和屬性

  • state中儲存著共有資料,資料是響應式的
  • getter可以對state進行計算操作,主要用來過濾一些資料,可以在多元件之間複用
  • mutations定義的方法動態修改state中的資料,通過commit提交方法,方法必須是同步的
  • actions將mutations裡面處理資料的方法變成非同步的,就是非同步運算元據,通store.dispatch來分發actions,把非同步的方法寫在actions中,通過commit提交mutations,進行修改資料。
  • modules:模組化vuex

7.vue路由的兩種模式

  • hash ——即位址列URL中的#符號(此hsah 不是密碼學裡的雜湊運算) hash 雖然出現URL中,但不會被包含在HTTP請求中,對後端完全沒有影響,因此改變hash不會重新載入頁面。
  • history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法

這兩個方法應用於瀏覽器的歷史記錄站,在當前已有的back、forward、go 的基礎之上,它們提供了對歷史記錄進行修改的功能。只是當它們執行修改是,雖然改變了當前的URL,但你瀏覽器不會立即向後端傳送請求。

8.vue中 key 值的作用

當 Vue.js 用v-for正在更新已渲染過的元素列表時,它預設用“就地複用”策略。 如果資料項的順序被改變,Vue 將不會移動 DOM 元素來匹配資料項的順序,而是簡單複用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。

key的作用主要是為了高效的更新虛擬DOM。

9$route$router的區別

  • $route是“路由資訊物件”,包括path,params,hash,query,fullPath,matched,name等路由資訊引數。
  • $router是“路由例項”物件包括了路由的跳轉方法,鉤子函式等。

10.vue-router守衛

  • 導航守衛 router.beforeEach 全域性前置守衛
  • to: Route: 即將要進入的目標(路由物件)
  • from: Route: 當前導航正要離開的路由
  • next: Function: 一定要呼叫該方法來 resolve 這個鉤子。(一定要用這個函式才能去到下一個路由,如果不用就攔截) 執行效果依賴 next 方法的呼叫引數。
  • next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
  • next(false): 取消進入路由,url地址重置為from路由地址(也就是將要離開的路由地址)。
// main.js 入口檔案
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全域性後置鉤子');
    });

複製程式碼

路由獨享的守衛 你可以在路由配置上直接定義 beforeEnter 守衛

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
複製程式碼

元件內的守衛 你可以在路由元件內直接定義以下路由導航守衛

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該元件的對應路由被 confirm 前呼叫
    // 不!能!獲取元件例項 `this`
    // 因為當守衛執行前,元件例項還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,但是該元件被複用時呼叫
    // 舉例來說,對於一個帶有動態引數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 由於會渲染同樣的 Foo 元件,因此元件例項會被複用。而這個鉤子就會在這個情況下被呼叫。
    // 可以訪問元件例項 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該元件的對應路由時呼叫,我們用它來禁止使用者離開
    // 可以訪問元件例項 `this`
    // 比如還未儲存草稿,或者在使用者離開前,
    將setInterval銷燬,防止離開之後,定時器還在呼叫。
  }
}
複製程式碼

11.axios是什麼?怎麼使用?描述使用它實現登入功能的流程?

請求後臺資源的模組。

$ npm install axios -S裝好
複製程式碼

然後傳送的是跨域,需在配置檔案中config/index.js進行設定。後臺如果是Tp5則定義一個資源路由。 js中使用import進來,然後.get或.post。返回在.then函式中如果成功,失敗則是在.catch函式中

12.vue修飾符

  • stop:阻止事件的冒泡
  • prevent:阻止事件的預設行為
  • once:只觸發一次
  • self:只觸發自己的事件行為時,才會執行

13.vue專案中的效能優化

1.不要在模板裡面寫過多表示式

2.迴圈呼叫子元件時新增key

3.頻繁切換的使用v-show,不頻繁切換的使用v-if

4.儘量少用float,可以用flex

5.按需載入,可以用require或者import()按需載入需要的元件

6.路由懶載入

14.vue.extend和vue.component

  • extend 是構造一個元件的語法器。 然後這個元件你可以作用到Vue.component這個全域性註冊方法裡 還可以在任意vue模板裡使用元件。 也可以作用到vue例項或者某個元件中的components屬性中並在內部使用apple元件。
  • Vue.component 你可以建立 ,也可以取元件。

常見的相容問題

png24位的圖片在iE6瀏覽器上出現背景 解決方案是做成PNG8.也可以引用一段指令碼處理.

瀏覽器預設的margin和padding不同。 解決方案是加一個全域性的*{margin:0;padding:0;}來統一。

IE6雙邊距bug:塊屬性標籤float後,又有橫行的margin情況下,在ie6顯示margin比設定的大。

浮動ie產生的雙倍距離(IE6雙邊距問題:在IE6下,如果對元素設定了浮動,同時又設定了margin-left或margin-right,margin值會加倍。) #box{ float:left; width:10px; margin:0 0 0 100px;}

React問題

1.react和vue的區別

   =>  相同點:
	1.資料驅動頁面,提供響應式的試圖元件
	2.都有virtual DOM,元件化的開發,通過props引數進行父子之間元件傳遞資料,都實現了webComponents規範
	3.資料流動單向,都支援伺服器的渲染SSR
	4.都有支援native的方法,react有React native, vue有wexx
=>  不同點:
	1.資料繫結:Vue實現了雙向的資料繫結,react資料流動是單向的
	2.資料渲染:大規模的資料渲染,react更快
	3.使用場景:React配合Redux架構適合大規模多人協作複雜專案,Vue適合小快的專案
	4.開發風格:react推薦做法jsx + inline style把html和css都寫在js了
		    vue是採用webpack + vue-loader單檔案元件格式,html, js, css同一個檔案
複製程式碼

2.redux中的reducer(純函式)

Redux資料流裡,reduces其實是根據之前的狀態(previous state)和現有的action(current action)
更新state(這個state可以理解為上下累加器的結果)
每次redux reducer被執行時,state和action被傳入,這個state根據action進行累加或者是'自身消減'(reduce),
進而返回最新的state,這也就是典型reduce函式的用法:state ->  action ->  state
複製程式碼

3.react的refs

refs就想一個逃生窗,允許我們之間訪問dom元素或者元件例項,可以向元件新增一個ref屬性的值是一個回撥函式,
它將接受地城dom元素或元件的已掛在例項,作為第一個引數
複製程式碼

4.react中的keys

幫組我們跟蹤哪些專案已更改、新增、從列表中刪除,key是獨一無二的,可以讓我們高效的去定位元素,並且操作它
複製程式碼

5.React的生命週期

三個狀態:Mounting(已插入真實的DOM)
	  Updating(正在被重新渲染)
	  Unmounting(已移除真實的DOM)
componentDIdMount 在第一次渲染後呼叫,只在客服端。之後元件已經生成對應的DOM結構,
componentDidUpdate 在元件完成更新後立即呼叫,在出初始化是不會呼叫
複製程式碼

6.React子元件向父元件傳值

父元件通過props 給子元件傳遞資料,子元件則是通過呼叫父元件傳給它的函式給父元件傳遞資料。
複製程式碼

7.為什麼虛擬DOM會提高效能 www.zhihu.com/question/29…

虛擬DOM相當於在js和真實dom中間加了一個快取,利用dom diff演算法避免了沒有必要的doom操作,從而提高效能
具體實現步驟:
	·用JavaScript物件結構表示DOM樹的結構;然後用這個樹構建一個真正的DOM樹,插到文件中
        ·當狀態變更的時候,重新構造一棵樹的物件樹,然後用新的樹和舊的樹進行對比,記錄兩棵樹差異
	·把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,試圖就更新了。
複製程式碼

8.diff演算法

1.把樹形結構按照層級分解,只比較同級元素
2.給列表結構的每個單元新增key屬性,方便比較。在實際程式碼中,會對新舊兩棵樹進行一個深度優先的遍歷,這樣每個節點都會有一個標記
3.在深度優先遍歷的時候,每遍歷到一個節點就把該節點和新的樹進行對比。如果有差異的話就記錄到一個物件裡面
Vritual DOM 演算法主要實現上面步驟的三個函式:element, diff, patch。然後就可以實際的進行使用
react只會匹配相同的class的component(這裡的class指的是元件的名字)
合併操作,條用component的setState方法的時候,React將其標記為dirty.到每一個時間迴圈借宿,React檢查所有標記dirty的component重新繪製
4.選擇性子樹渲染。可以重寫shouldComponentUpdate提高diff的效能	
複製程式碼

9.簡述下flux的思想

flux的最大特點,就是資料的‘單向流動’
1.使用者訪問View
2.View發出使用者的Action
3.Dispatcher收到Action,要求state進行相應的更新
4.store更新後,發出一個‘change’事件後,更新頁面
複製程式碼

10.reac效能優化是哪個週期函

shouldComponentUpdate 這個方法用來判斷是否需要呼叫render方法重新描繪dom.因為dom的描繪非常消耗效能,
如果我們在shouldComponentUpdate方法中能夠寫出更優化的dom diff演算法,可以極大的提高效能
複製程式碼

11.react怎麼劃分業務元件和技術元件

根據元件的職責通常把元件分為UI元件和容器元件
UI元件負責UI的呈現,容器元件負責管理資料和邏輯
兩者通過React-redux提供connect方法聯絡起來
複製程式碼

12.setState

setState通過一個佇列機制實現state更新,當執行setState時,會將需要更新的state很後放入狀態佇列
而不會立即更新this.state,佇列機制可以高效地批量更新state。如果不通過setState而直接修改this.state的值	
那麼該state將不會被放入狀態佇列中。當下次呼叫setState並對狀態佇列進行合併時,就會忽略之前修改的state,造成不可預知的錯誤

同時,也利用了佇列機制實現了setState的非同步更新,避免了頻繁的重複更新state

同步更新state:
	setState 函式並不會阻塞等待狀態更新完畢,因此 setNetworkActivityIndicatorVisible 有可能先於資料渲染完畢就執行。
	第二個引數是一個回撥函式,在setState的非同步操作結束並且元件已經重新渲染的時候執行
	也就是說,我們可以通過這個回撥來拿到更新的state的值,實現程式碼的同步

例子:componentDidMount() {

	fetch('https://test.com')
    
	.then((res) => res.json())
    
	.then(
    (data) => {
this.setState({ data:data });
			StatusBar.setNetworkActivityIndicatorVisible(false);
        }
複製程式碼

效能優化

一、webpack打包檔案體積過大?(最終打包為一個js檔案)

1.非同步載入模組
2.提取第三庫
3.程式碼壓縮
4.去除不必要的外掛
複製程式碼

二、如何優化webpack構建的效能

一、減少程式碼體積 1.使用CommonsChunksPlugin 提取多個chunk之間的通用模組,減少總體程式碼體積
		 2.把部分依賴轉移到CDN上,避免每次編譯過程都由Webpack處理
		 3.對一些元件庫採用按需載入,避免無用的程式碼
二、減少目錄檢索範圍
		 ·在使用loader的時候,通過制定exclude和include選項,減少loader遍歷的目錄範圍,從而加快webpack編譯速度
	
三、減少檢索路經:resolve.alias可以配置webpack模組解析的別名,對於比較深的解析路經,可以對其配置alias
複製程式碼

三、移動端的效能優化

  1、首屏載入和按需載入,懶載入
  2、資源預載入
  3、圖片壓縮處理,使用base64內嵌圖片
  4、合理快取dom物件
  5、使用touchstart代替click(click 300毫秒的延遲)
  6、利用transform:translateZ(0),開啟硬體GUP加速
  7、不濫用web字型,不濫用float(佈局計算消耗效能),減少font-size宣告
  8、使用viewport固定螢幕渲染,加速頁面渲染內容
  9、儘量使用事件代理,避免直接事件繫結
複製程式碼

四、Vue的SPA 如何優化載入速度

1.減少入口檔案體積
2.靜態資源本地快取
3.開啟Gzip壓縮
4.使用SSR,nuxt.js
複製程式碼

五、移動端300ms延遲

由來:
300毫米延遲解決的是雙擊縮放。雙擊縮放,手指在螢幕快速點選兩次。safari瀏覽器就會將網頁縮放值原始比例。由於使用者可以雙擊縮放或者是滾動的操作,
當使用者點選螢幕一次之後,瀏覽器並不會判斷使用者確實要開啟至這個連結,還是想要進行雙擊操作
因此,safair瀏覽器就會等待300ms,用來判斷使用者是否在次點選了螢幕
       
解決方案:1.禁用縮放,設定meta標籤 user-scalable=no
	  2.fastclick.js
		原理:FastClick的實現原理是在檢查到touchend事件的時候,會通過dom自定義事件立即
		      發出click事件,並把瀏覽器在300ms之後真正的click事件阻止掉
fastclick.js還可以解決穿透問題
複製程式碼

六、頁面的重構;

在不改變外部行為的前提下,簡化結構、新增可讀性

伺服器端

一、狀態碼:

  2XX(成功處理了請求狀態)
      200 伺服器已經成功處理請求,並提供了請求的網頁
      201 使用者新建或修改資料成功
      202 一個請求已經進入後臺
      204 使用者刪除成功
  3XX(每次請求使用的重定向不要超過5次)
      304 網頁上次請求沒有更新,節省頻寬和開銷
  4XX(表示請求可能出錯,妨礙了伺服器的處理)
      400 伺服器不理解請求的語法
      401 使用者沒有許可權(使用者名稱,密碼輸入錯誤)
      403 使用者得到授權(401相反),但是訪問被禁止
      404 伺服器找不到請求的網頁,
  5XX(表示伺服器在處理請求的時候發生內部錯誤)
      500 伺服器遇到錯誤,無法完成請求
      503 伺服器目前無法使用(超載或停機維護)     
複製程式碼

二、304的快取原理(新增Etag標籤.last-modified) 304 網頁上次請求沒有更新,節省頻寬和開銷

1.伺服器首先產生Etag,伺服器可在稍後使用它來判斷頁面是否被修改。本質上,客戶端通過該記號傳回伺服器要求伺服器驗證(客戶端)快取)
2.304是	HTTP的狀態碼,伺服器用來標識這個檔案沒有被修改,不返回內容,瀏覽器接受到這個狀態碼會去去找瀏覽器快取的檔案
3.流程:客戶端請求一個頁面A。伺服器返回頁面A,並在A上加一個Tage客服端渲染該頁面,並把Tage也儲存在快取中。客戶端再次請求頁面A
	並將上次請求的資源和ETage一起傳遞給伺服器。伺服器檢查Tage.並且判斷出該頁面自上次客戶端請求之後未被修改。直接返回304

last-modified: 客服端請求資源,同時有一個last-modified的屬性標記此檔案在伺服器最後修改的時間
		客服端第二次請求此url時,根據http協議。瀏覽器會向伺服器傳送一個If-Modified-Since報頭,
		詢問該事件之後檔案是否被修改,沒修改返回304

 有了Last-Modified,為什麼還要用ETag?
  1、因為如果在一秒鐘之內對一個檔案進行兩次更改,Last-Modified就會不正確(Last—Modified不能識別秒單位的修改)
  2、某些伺服器不能精確的得到檔案的最後修改時間
  3、一些檔案也行會週期新的更改,但是他的內容並不改變(僅僅改變修改的事件),這個時候我們並不希望客戶端認為檔案被修改,而重新Get

ETag,為什麼還要用Last-Modified?
  1、兩者互補,ETag的判斷的缺陷,比如一些圖片等靜態檔案的修改
  2、如果每次掃描內容都生成ETag比較,顯然要比直接比較修改時間慢的多。


ETag是被請求變數的實體值(檔案的索引節,大小和最後修改的時間的Hash值)
  1、ETag的值伺服器端對檔案的索引節,大小和最後的修改的事件進行Hash後得到的。
複製程式碼

三、get/post的區別

1.get資料是存放在url之後,以?分割url和傳輸資料,引數之間以&相連; post方法是把提交的資料放在http包的Body中
2.get提交的資料大小有限制,(因為瀏覽器對url的長度有限制),post的方法提交的資料沒有限制
3.get需要request.queryString來獲取變數的值,而post方式通過request.from來獲取變數的值
4.get的方法提交資料,會帶來安全問題,比如登入一個頁面,通過get的方式提交資料,使用者名稱和密碼就會出現在url上
複製程式碼

四、http協議的理解

1.超文字的傳輸協議,是用於從全球資訊網伺服器超文字傳輸到本地資源的傳輸協議
2.基於TCP/IP通訊協議來傳遞資料(HTML,圖片資源)
3.基於運用層的物件導向的協議,由於其簡潔、快速的方法、適用於分散式超媒體資訊系統
4.http請求資訊request:
	請求行(request line)、請求頭部(header),空行和請求資料四部分構成

	請求行,用來說明請求型別,要訪問的資源以及所使用的HTTP版本.
	請求頭部,用來說明伺服器要使用的附加資訊
	空行,請求頭部後面的空行是必須的
	請求資料也叫主體,可以新增任意的其他資料。
5.http相應資訊Response
	狀態行、訊息報頭、空行和響應正文

	狀態行,由HTTP協議版本號, 狀態碼, 狀態訊息 三部分組成
	訊息報頭,用來說明客戶端要使用的一些附加資訊
	空行,訊息報頭後面的空行是必須的
	響應正文,伺服器返回給客戶端的文字資訊。
複製程式碼

五、http和https

https:是以安全為目標的HTTP通道,簡單講是HTTP的安全版本,通過SSL加密
http:超文字傳輸協議。是一個客服端和伺服器端請求和應答的標準(tcp),使瀏覽器更加高效,使網路傳輸減少
複製程式碼

六、http1.0 1.1 2.0的區別

長連線:HTTP1.0需要使用keep-alive引數來告知伺服器建立一個長連線,而HTP1.1預設支援長連線
節約寬頻:HTTP1.1支援只傳送一個header資訊(不帶任何body資訊)
host域(設定虛擬站點,也就是說,web server上的多個虛擬站點可以共享同一個ip埠):HTTP1.0沒有host域

1.http2採用的二進位制文字傳輸資料,而非http1文字格式,二進位制在協議的解析和擴充套件更好
2.資料壓縮:對資訊頭採用了HPACK進行壓縮傳輸,節省了資訊頭帶來的網路流量
3.多路複用:一個連線可以併發處理多個請求
4.伺服器推送:我們對支援HTTP2.0的web server請求資料的時候,伺服器會順便把一些客戶端需要的資源一起推送到客戶端,免得客戶端再次建立連線傳送請求到伺服器端獲取。這種方式非常合適載入靜態資源
複製程式碼

七、web快取

1.web快取就是存在於客戶端與伺服器之間的一個副本、當你第一個發出請求後,快取根據請求儲存輸出內容的副本
2.快取的好處
        (1)減少不必要的請求
    (2)降低伺服器的壓力,減少伺服器的消耗
    (3)降低網路延遲,加快頁面開啟速度(直接讀取瀏覽器的資料)
複製程式碼

八、常見的web安全及防護原理

1.sql注入原理:是將sql程式碼偽裝到輸入引數中,傳遞到伺服器解析並執行的一種攻擊手法。也就是說,
            在一些對server端發起的請求引數中植入一些sql程式碼,server端在執行sql操作時,會拼接對應引數,
            同時也將一些sql注入攻擊的“sql”拼接起來,導致會執行一些預期之外的操作。
		防範:1.對使用者輸入進行校驗
		       2.不適用動態拼接sql
2.XSS(跨站指令碼攻擊):往web頁面插入惡意的html標籤或者js程式碼。
		        舉例子:在論壇放置一個看是安全的連結,竊取cookie中的使用者資訊
			防範:1.儘量採用post而不使用get提交表單
			      2.避免cookie中洩漏使用者的隱式
3.CSRF(跨站請求偽裝):通過偽裝來自受信任使用者的請求
			舉例子:黃軼老師的webapp音樂請求資料就是利用CSRF跨站請求偽裝來獲取QQ音樂的資料
			防範:在客服端頁面增加偽隨機數,通過驗證碼
XSS和CSRF的區別:
   1.XSS是獲取資訊,不需要提前知道其他使用者頁面的程式碼和資料包
   2.CSRF代替使用者完成指定的動作,需要知道其他頁面的程式碼和資料包
複製程式碼

九、CDN(內容分發網路)

1.儘可能的避開網際網路有可能影響資料傳輸速度和穩定性的瓶頸和環節。使內容傳輸的更快更穩定。
2.關鍵技術:內容儲存和分發技術中
3.基本原理:廣泛採用各種快取伺服器,將這些快取伺服器分佈到使用者訪問相對的地區或者網路中。當使用者訪問網路時利用全域性負載技術
	    將使用者的訪問指向距離最近的快取伺服器,由快取伺服器直接相應使用者的請求(全域性負載技術)
複製程式碼

十、TCP三次握手 (客服端和伺服器端都需要確認各自可收發)

客服端發c起請求連線伺服器端s確認,伺服器端也發起連線確認客服端確認。
第一次握手:客服端傳送一個請求連線,伺服器端只能確認自己可以接受客服端傳送的報文段
第二次握手: 服務端向客服端傳送一個連結,確認客服端收到自己傳送的報文段
第三次握手: 伺服器端確認客服端收到了自己傳送的報文段
複製程式碼

十一、從輸入url到獲取頁面的完整過程 blog.csdn.net/samjustin1/…

1.查詢NDS(域名解析),獲取域名對應的IP地址  查詢瀏覽器快取
2.瀏覽器與伺服器建立tcp連結(三次握手)
3.瀏覽器向伺服器傳送http請求(請求和傳輸資料)
4.伺服器接受到這個請求後,根據路經引數,經過後端的一些處理生成html程式碼返回給瀏覽器
5.瀏覽器拿到完整的html頁面程式碼開始解析和渲染,如果遇到外部的css或者js,圖片一樣的步驟
6.瀏覽器根據拿到的資源對頁面進行渲染,把一個完整的頁面呈現出來
複製程式碼

十二、瀏覽器渲染原理及流程 DOM -> CSSOM -> render -> layout -> print

流程:解析html以及構建dom樹 -> 構建render樹 ->  佈局render樹 -> 繪製render樹
概念:1.構建DOM樹: 渲染引擎解析HTML文件,首先將標籤轉換成DOM樹中的DOM node(包括js生成的標籤)生成內容樹
      2.構建渲染樹: 解析對應的css樣式檔案資訊(包括js生成的樣式和外部的css)
      3.佈局渲染樹:從根節點遞迴呼叫,計算每一個元素的大小,位置等。給出每個節點所在的螢幕的精準位置
      4.繪製渲染樹:遍歷渲染樹,使用UI後端層來繪製每一個節點

重繪:當盒子的位置、大小以及其他屬性,例如顏色、字型大小等到確定下來之後,瀏覽器便把這些顏色都按照各自的特性繪製一遍,將內容呈現在頁面上
	觸發重繪的條件:改變元素外觀屬性。如:color,background-color等
	重繪是指一個元素外觀的改變所觸發的瀏覽器行為,瀏覽器會根據元素的新屬性重新繪製,使元素呈現新的外觀
注意:table及其內部元素需要多次計算才能確定好其在渲染樹中節點的屬性值,比同等元素要多發時間,要儘量避免使用table佈局

重排(重構/迴流/reflow): 當渲染書中的一部分(或全部)因為元素的規模尺寸,佈局,隱藏等改變而需要重新構建,這就是迴流。
	每個頁面都需要一次迴流,就是頁面第一次渲染的時候

重排一定會影響重繪,但是重繪不一定會影響重排
複製程式碼

十三、為什麼css放在頂部而js寫在後面

1.瀏覽器預先載入css後,可以不必等待HTML載入完畢就可以渲染頁面了
2.其實HTML渲染並不會等到完全載入完在渲染頁面,而是一邊解析DOM一邊渲染。
3.js寫在尾部,主要是因為js主要扮演事件處理的功能,一方面很多操作是在頁面渲染後才執行的。另一方面可以節省載入時間,使頁面能夠更加的載入,提高使用者的良好體驗

但是隨著JS技術的發展,JS也開始承擔頁面渲染的工作。比如我們的UI其實可以分被對待,把渲染頁面的js放在前面,時間處理的js放在後面
複製程式碼

十四、儲存方式與傳輸方式

1.indexBD: 是h5的本地儲存庫,把一些資料儲存到瀏覽器中,沒網路,瀏覽器可以從這裡讀取資料,離線運用。5m
2.Cookie: 通過瀏覽器記錄資訊確認使用者身份,最大4kb,這也就限制了傳輸的資料,請求的效能會受到影響
3.Session: 伺服器端使用的一種記錄客戶狀態的機制(session_id存在set_cookie傳送到客服端,儲存為cookie)
4.localStroage: h5的本地儲存,資料永久儲存在客服端
複製程式碼

cookie,sessionStorage,localStorage

1、cookie,sessionStorage,localStorage是存放在客戶端,session物件資料是存放在伺服器上 實際上瀏覽器和伺服器之間僅需傳遞session id即可,伺服器根據session-id找到對應的使用者session物件 session儲存資料更安全一些,一般存放使用者資訊,瀏覽器只適合儲存一般的資料 2、cookie資料始終在同源的http請求中攜帶,在瀏覽器和伺服器來回傳遞,裡面存放著session-id sessionStorage,localStorage僅在本地儲存 3、大小限制區別,cookie資料不超過4kb,localStorage在谷歌瀏覽中2.6MB 4、資料有效期不同,cookie在設定的(伺服器設定)有效期內有效,不管視窗和瀏覽器關閉 sessionStorage僅在當前瀏覽器視窗關閉前有效,關閉即銷燬(臨時儲存) localStorage始終有效

SessionStorage和localStorage區別: 1.sessionStorage用於本地儲存一個會話(session)中的資料,這些資料只有在用一個會話的頁面中才能被訪問(也就是說在第一次通訊過程中) 並且在會話結束後資料也隨之銷燬,不是一個持久的本地儲存,會話級別的儲存 2.localStorage用於持久化的本地儲存,除非主動刪除資料,否則不會過期

token、cookie、session三者的理解???!!!

1、token就是令牌,比如你授權(登入)一個程式時,他就是個依據,判斷你是否已經授權該軟體(最好的身份認證,安全性好,且是唯一的)
    使用者身份的驗證方式    

2、cookie是寫在客戶端一個txt檔案,裡面包括登入資訊之類的,這樣你下次在登入某個網站,就會自動呼叫cookie自動登入使用者名稱
    伺服器生成,傳送到瀏覽器、瀏覽器儲存,下次請求再次傳送給伺服器(存放著登入資訊)

3、session是一類用來客戶端和伺服器之間儲存狀態的解決方案,會話完成被銷燬(代表的就是伺服器和客戶端的一次會話過程)
    cookie中存放著sessionID,請求會傳送這個id。sesion因為request物件而產生。
複製程式碼

基於Token的身份驗證:(最簡單的token: uid使用者唯一的身份識別 + time當前事件戳 + sign簽名)

  1、使用者通過使用者名稱和密碼傳送請求
  2、伺服器端驗證
  3、伺服器端返回一個帶簽名的token,給客戶端
  4、客戶端儲存token,並且每次用於傳送請求
  5、伺服器驗證token並且返回資料
  每一次請求都需要token
複製程式碼

cookie與session區別

  1、cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。
  2、cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙考慮到安全應當使用session。
  3、session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能考慮到減輕伺服器效能方面,應當使用COOKIE。
  4、單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。
複製程式碼

session與token區別

  1、session認證只是把簡單的User的資訊儲存Session裡面,sessionID不可預測,一種認證手段。只存在服務端,不能共享到其他的網站和第三方App
  2、token是oAuth Token,提供的是認證和授權,認證針對使用者,授權是針對App,目的就是讓某APP有權訪問某使用者的的資訊。Token是唯一的,
     token不能轉移到其他的App,也不能轉到其他使用者上。(適用於App)
  3、session的狀態是存在伺服器端的,客戶端只存在session id, Token狀態是儲存在客戶端的
複製程式碼

Cookie的弊端有哪些???(優勢:儲存客戶端資料,分擔了伺服器儲存的負擔)

  1、數量和長度的限制。每個特定的域名下最多生成20個cookie(chorme和safari沒有限制)
  2、安全性問題。
複製程式碼

設計模式

一、觀察者模式:juejin.im/post/5a14e9… juejin.im/post/5af05d… 在軟體開發設計中是一個物件(subject),維護一系列依賴他的物件(observer),當任何狀態發生改變自動通知他們。強依賴關係 簡單理解:資料發生改變時,對應的處理函式就會自動執行。一個Subjet,用來維護Observers,為某些event來通知(notify)觀察者

二、釋出-訂閱者 有一個資訊中介,過濾 耦合性低 它定義了一種一對多的關係,可以使多個觀察者物件對一個主題物件進行監聽,當這個主題物件發生改變時,依賴的所有物件都會被通知到。

  • -兩者的區別: 1.觀察者模式中,觀察者知道Subject ,兩者是相關聯的,而發發布訂閱者只有通過資訊代理進行通訊 2.在釋出訂閱模式中,元件式鬆散耦合的。正好和觀察者模式相反。 3.觀察者大部分是同步的,比如事件的觸發。Subject就會呼叫觀察者的方法。而釋出訂閱者大多數是非同步的() 4.觀察者模式需要在單個應用程式地址空間中實現,而釋出訂閱者更像交叉應用模式。

資料結構和演算法

一、兩個棧實現一個佇列,兩個佇列實現一個棧 www.cnblogs.com/MrListening…

二、紅黑樹(解決二叉樹依次插入多個節點時的線型排列) juejin.im/post/5a27c6…

三、最小棧的實現(查詢最小元素,用兩個棧配合棧內元素的下標)juejin.im/post/5a2ff8…

四、十大排序

1.氣泡排序:重複走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把它們交換過來。
  實現過程:1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個
	    2.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數
	    3.針對所有的元素重複以上的步驟,除了最後一個
	    4.重複步驟1-3,直到排序完成。
2.選擇排序:首先在未排序序列中找到最小值,放在排序序列的起始位置,然後,在從剩下未排序元素中繼續尋找最小值,然後放在與排序序列的末尾
  實現過程:

3.插入排序:構建有序序列,對於未排序資料,在已排序序列中衝後向前掃描,找到相應位置並插入
  實現過程:1.從第一個元素開始,該元素可以認為已經被排序
	    2.取出下一個元素,在已排序的元素序列中衝後向前掃描
	    3.如果該元素(以排序)大於新元素,將元素向後移一位
	    4.在取出一個元素,比較之前的,直到找到自己合適的位置

4.桶排序:將資料分佈到有限數量的桶裡,每個桶在分別排序

1.快速排序:快速排序使用分治法把一個串(list)分為兩個子串(sub-lists).具體演算法實現
  實現過程:1.從陣列中挑出一個元素,成為一個基準
	    2.重新排列陣列,所有元素比基準小的擺在基準前面,所有元素比基準大的擺在基準後面(相同的可以擺在一邊)
		這個分割槽退出之後,該基準就處於數列的中間位置。成為分割槽操作。
	    3.遞迴的把小於基準值的子數列和大於基準值元素的子數列排序
演算法實現: function quickSort (arr) {
		if (arr.length <= 1) {return arr}
		var destIndex = Math.floor(arr.length/2)
		var left = [], right = [];
		var dest = arr.splice(destIndex,1)[0];
		for (var i =0;i<arr.length;i++){
			if (arr[i]<dest) {
			left.push(arr[i])
			} else {
			right.push(arr[i]) }
		return quickSort(left).concat([dest],quickSort(right)
			

2.堆排序:利用對這種資料結構所涉及的一種排序演算法,堆積是一個近乎完全二叉樹的結構,並同時滿足堆積的性質:即子節點的鍵值或索引總是小於(或大於)它的父節點。
  實現過程:1.
複製程式碼

五、陣列去重 juejin.im/post/5aed61…

1.雙重迴圈
2.indexOf
3.陣列排序去重 最快你Olong
複製程式碼

六、字串

判斷迴文字串:(遞迴的思想)
	1.字串分隔,倒轉,聚合[...obj].reverse().join('')
	2.字串頭部和尾部,逐次向中間檢測 
		實現:function isPalindrome(line) {
			line += '';
			for (var i=0,j=line.length-1;i<j;i++,j--) {
				if (line.chartAt(i) !== line.chartAt(j) {
				return false
			}
			
	3.遞迴
複製程式碼

七、二分查詢(有序陣列的查詢)

 二分查詢可以解決已排序陣列的查詢問題,即只要陣列中包含T(要查詢的值),那麼通過不斷的縮小包含T的資料範圍,就可以最終要找到的數
 (1) 一開始,資料範圍覆蓋整個陣列。
 (2) 將陣列的中間項與T進行比較,如果T比陣列的中間項小,則到陣列的前半部分繼續查詢,反之,則到陣列的後半部分繼續查詢。
 (3) 就這樣,每次查詢都可以排除一半元素,相當於範圍縮小一半。這樣反覆比較,反覆縮小範圍,最終會在陣列中找到T
程式碼實現:function binarySearch (data, dest, start, end){
		var end = end || data.length-1;
		var start = start || 0;
		var m = Math.floor((start+end)/2);
		if (dest<data[m]){
			return binarySearch(data, dest, 0, m-1)
		} else {
			return binarySearch(data, dest, m+1, end)
		}}
		return false
複製程式碼

手寫程式碼

一、動手實現一個bind(原理通過apply,call)

一句話概括:1.bind()返回一個新函式,並不會立即執行。
	    2.bind的第一個引數將作為他執行時的this,之後的一系列引數將會在傳遞的實參前傳入作為他的引數
	    3.bind返回函式作為建構函式,就是可以new的,bind時指定的this值就會消失,但傳入的引數依然生效
複製程式碼
Function.prototype.bind = function (obj, arg) {
   var arg = Array.prototype.slice.call(arguments, 1);
   var context = this;
   var bound = function (newArg) {
   arg = arg.concat(Array.prototype.slice.call(newArg);
   return context.apply(obj, arg)
}
  var F =  function () {}  // 在new一個bind會生成新函式,必須的條件就是要繼承原函式的原型,因此用到寄生繼承來完成我們的過程
  F.prototype = context.prototype;
  bound.prototype =  new F();
  return bound;
}	
複製程式碼

二、 AJAX (非同步的javascript和xml)

ajax的原理:相當於在使用者和伺服器之間加一箇中間層(ajax引擎),使使用者操作與伺服器響應非同步化。
優點:在不重新整理整個頁面的前提下與伺服器通訊維護資料。不會導致頁面的過載
      可以把前端伺服器的任務轉嫁到客服端來處理,減輕伺服器負擔,節省寬頻
劣勢:不支援back。對搜尋引擎的支援比較弱;不容易除錯	
怎麼解決呢?通過location.hash值來解決Ajax過程中導致的瀏覽器前進後退按鍵失效,
解決以前被人常遇到的重複載入的問題。主要比較前後的hash值,看其是否相等,在判斷是否觸發ajax
複製程式碼
function getData(url) {
    var xhr = new XMLHttpRequest();  // 建立一個物件,建立一個非同步呼叫的物件
    xhr.open('get', url, true)  // 設定一個http請求,設定請求的方式,url以及驗證身份
    xhr.send() //傳送一個http請求
    xhr.onreadystatechange = function () {  //設定一個http請求狀態的函式
      if (xhr.readyState == 4 && xhr.status ==200) {
        console.log(xhr.responseText)  // 獲取非同步呼叫返回的資料
      }
    }
  }
  Promise(getData(url)).resolve(data => data)

	 AJAX狀態碼:0 - (未初始化)還沒有呼叫send()方法
		     1 - (載入)已呼叫send方法,正在傳送請求
		     2 - (載入完成呢)send()方法執行完成
		     3 - (互動)正在解析相應內容
		     4 - (完成)響應內容解析完成,可以在客戶端呼叫了
```

#### 三、函式節流(throttle)
```
 function throttle (func, wait) {
        var timeout;
        var previous = 0;
        return function () {
            context = this;
            args = arguments;
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context,args)
                }, wait);
            }
        }
    }
     
}
```

#### 四、函式防抖(dobounce)
```
 function debounce (func, wait) {
         var timeout;
         return function() {
             var context = this;
             var args = arguments;
             clearTimeout(timeout);
             timeout = setTimeout(() => {
                 func.apply(context,args)
             }, wait);
         }
     }
```

#### 五、實現一個函式clone,可以對JavaScript中的5種主要的資料型別(包括Number、String、Object、Array、Boolean)進行值複製
```    
    Object.prototype.clone = function() {
      var newObject = this.constructor === Array ? [] : {}  //物件的深拷貝 獲取對應的建構函式 [] 或者 {}
      for (let e in this) { //遍歷物件的屬性 in  this[e]
        newObject[e] = typeof this[e] === 'object' ? this[e].clone() : this[e]  //物件中的屬性如果還是物件 那就繼續遞迴 否則就返回基本的資料型別
      }
      return newObject
    }
```
 
#### 六、實現一個簡單的Promise https://juejin.im/post/5b2f02cd5188252b937548ab
```
class Promise {
  constructor (executor) {   // executor裡面有兩個引數,一個叫resolve(成功),一個叫reject(失敗)。
    this.status = 'pending',
    this.value = undefined;
    this.reason = undefined;
    // 成功存放的陣列
    this.onResolvedCallbacks = [];
     // 失敗存放法陣列
     this.onRejectedCallbacks = [];
    let resolve = (value) => {
      if (this.status == 'pending') {
        this.status = 'resolve';
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    let reject = (reason) => {
      if (this.status == 'pending') {
        this.status = 'reject';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  } 
  then (onFullFilled,onRejected) {
    if (this.status == 'resolved') {
      onFullFilled(this.value)
    }
    if (this.status == 'rejectd') {
      onRejected(this.reason);
    }
    if (this.status == 'pending') {
      this.onResolvedCallbacks.push(()=>{
        onFullFilled(this.value);
      })
      this.onRejectedCallbacks.push(()=> {
          onRejected(this.reason);
      })
  }
   
  }
}

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
      resolve('hello world')
  }, 1000);
})
p.then((data) =>{
  console.log(data)
},(err) =>{
  console.log(err);
})
```

#### 七、釋出訂閱者模式(觀察者模式)
```
var event = {}; // 釋出者
event.clientList = [] //釋出者的快取列表

event.listen = function (fn) {  // 增加訂閱者函式
  this.clientList.push(fn)
}

event.trigger = function () {  // 釋出資訊
  for (var i =0;i<this.clientList.length;i++) {
    var fn = this.clientList[i];
    fn.apply(this, arguments);
  }
}

event.listen (function(time) {
  console.log('正式上班時間為:' +time)
})
event.trigger ('2018/7')
```

#### 八、手動寫一個node伺服器
```
const http = require('http');
const fs = require('fs');
const server = http.createServer((req,res) => {
	if (reu.url == '/') {
	const indexFile = fs.createReadStream('./index.html')
	req.writeHead(200,{'context-Type':'text/html;charset = utf8})
	indexFile.pipe(res)
}
server.listen(8080)
```複製程式碼

相關文章