歡迎評論區糾錯完善
css部分
實現三欄佈局
(兩側定寬,中間自適應)
- 採用了 absolute,導致父元素脫離了文件流,那所有的子元素也需要脫離文件流。如果頁面複雜,那開發的難度可想而知
- 利用浮動 當中間內容高於兩側時,兩側高度不會隨中間內容變高而變高
- 彈性盒子佈局
- 利用負邊距和浮動,實現起來比較複雜
- 利用網格佈局
.container {
display: grid;
grid-template-columns: 100px auto 200px;
}
複製程式碼
BFC(塊級格式化上下文)
BFC 的原理 其實也就是 BFC 的渲染規則(能說出以下四點就夠了)。包括:
- BFC 內部的子元素,在垂直方向,邊距會發生重疊。
- BFC在頁面中是獨立的容器,外面的元素不會影響裡面的元素,反之亦然。(稍後看舉例1)
- BFC區域不與旁邊的float box區域重疊。(可以用來清除浮動帶來的影響)。(稍後看舉例2)
- 計算BFC的高度時,浮動的子元素也參與計算。 如何生成BFC
- 方法1:overflow: 不為vidible,可以讓屬性是 hidden、auto。【最常用】
- 方法2:浮動中:float的屬性值不為none。意思是,只要設定了浮動,當前元素就建立了BFC。
- 方法3:定位中:只要posiiton的值不是 static或者是relative即可,可以是absolute或fixed,也就生成了一個BFC。
- 方法4:display為inline-block, table-cell, table-caption, flex, inline-flex
flex(略)
js部分
陣列去重
[...new Set(arr]
複製程式碼
var arr = [1,2,1,2,3,5,4,5,3,4,4,4,4],
init=[]
var result = arr.sort().reduce((init, current)=>{
console.log(init,current)
if(init.length===0 || init[init.length-1]!==current){
init.push(current);
}
return init;
}, []);
console.log(result);//1,2,3,4,5
複製程式碼
防抖節流
var deBounce=function(fn,wait=300){
let timer
return function(){
if(timer){
clearTimeOut(timer)
}
timer=setTimeOut(()=>{
fn.apply(this,arguments)
},wait)
}
}
var throttle=function(fn,wait=300){
let prev=+new Date();
return function(){
const args=argument,
now=+new Date();
if(now>last+wait){
last=now;
fn.apply(this,args)
}
}
}
複製程式碼
實現Promise思路
function Promise(fn) {
...
this._state = 0 // 狀態標記
doResolve(fn, this)
}
function doResolve(fn, self) {
var done = false // 保證只執行一個監聽
try {
fn(function(value) {
if (done) return
done = true
resolve(self, value)
},
function(reason) {
if (done) return;
done = true
reject(self, value)
})
} catch(err) {
if (done) return
done = true
reject(self, err)
}
}
function resolve(self, newValue) {
try {
self._state = 1;
...
}
catch(err) {
reject(self, err)
}
}
function reject(self, newValue) {
self._state = 2;
...
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
}
複製程式碼
正則實現千位分隔符
function commafy(num) {
return num && num
.toString()
.replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) {
return $1 + ",";
});
}
console.log(commafy(1312567.903000))
複製程式碼
js事件迴圈
javascript是單執行緒語言,任務設計成了兩類,同步任務和非同步任務 同步和非同步任務分別進入不同的執行“場所”,同步進入主執行緒,非同步進入Event Table並註冊函式。當指定的事情完成時,Event Table會將這個函式移入Event Queue。主執行緒內的任務執行完畢為空,回去了Event Queue讀取對應的函式,進入主執行緒。 上述過程會不斷重複,也就是常說的Event Loop(事件迴圈)。 但是,JS非同步還有一個機制,就是遇到巨集任務,先執行巨集任務,將巨集任務放入event queue,然後再執行微任務,將微任務放入eventqueue,但是,這兩個queue不是一個queue。當你往外拿的時候先從微任務裡拿這個回撥函式,然後再從巨集任務的queue拿巨集任務的回撥函式 巨集任務一般包括:整體程式碼script,setTimeout,setInterval。 微任務:Promise,process.nextTick
前端路由的兩種實現原理
- Hash模式
window物件提供了onhashchange事件來監聽hash值的改變,一旦url中的hash值發生改變,便會觸發該事件。 2. History 模式
- popstate監聽歷史棧資訊變化,變化時重新渲染
- 使用pushState方法實現新增功能
- 使用replaceState實現替換功能
封裝ajax
/* 封裝ajax函式
* @param {string}opt.type http連線的方式,包括POST和GET兩種方式
* @param {string}opt.url 傳送請求的url
* @param {boolean}opt.async 是否為非同步請求,true為非同步的,false為同步的
* @param {object}opt.data 傳送的引數,格式為物件型別
* @param {function}opt.success ajax傳送並接收成功呼叫的回撥函式
*/
function myAjax(opt){
opt = opt || {};
opt.method = opt.method.toUpperCase() || 'POST';
opt.url = opt.url || '';
opt.async = opt.async || true;
opt.data = opt.data || null;
opt.success = opt.success || function () {}
let xmlHttp = null;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}else{
xmlHttp =new ActiveXObject('Microsoft.XMLHTTP')
}
let params;
for (var key in opt.data){
params.push(key + '=' + opt.data[key]);
}
let postData = params.join('&');
if (opt.method.toUpperCase() === 'POST') {
xmlHttp.open(opt.method, opt.url, opt.async);
xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
xmlHttp.send(postData);
}else if (opt.method.toUpperCase() === 'GET') {
xmlHttp.open(opt.method, opt.url + '?' + postData, opt.async);
xmlHttp.send(null);
}
xmlHttp.onreadystatechange= function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
opt.success(xmlHttp.responseText);//如果是json資料可以在這使用opt.success(JSON.parse( xmlHttp.responseText))
}
};
}
複製程式碼
url拿引數
var url = "http://www.taobao.com/index.php?key0=0&key1=1&key2=2";
function parseQueryString(url){
var str = url.split("?")[1], //通過?得到一個陣列,取?後面的引數
items = str.split("&"); //分割成陣列
var arr,name,value;
for(var i=0; i<items.length; i++){
arr = items[i].split("="); //["key0", "0"]
name = arr[0];
value = arr[1];
this[name] = value;
}
}
var obj = new parseQueryString(url);
alert(obj.key2)
複製程式碼
HTTP部分
http協議
HTTP協議(超文字傳輸協議) 主要特點
- 簡單快速:客戶向伺服器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與伺服器聯絡的型別不同。由於HTTP協議簡單,使得HTTP伺服器的程式規模小,因而通訊速度很快。
- 靈活:HTTP允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。
- 無連線:無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。
- 無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。
- 支援B/S及C/S模式。
HTTP之請求訊息Request
- 請求行(request line)、請求頭部(header)、空行和請求資料四個部分組成。
- 請求行,用來說明請求型別,要訪問的資源以及所使用的HTTP版本.
- 請求頭部,緊接著請求行(即第一行)之後的部分,用來說明伺服器要使用的附加資訊
- 空行,請求頭部後面的空行是必須的
- 請求資料也叫主體,可以新增任意的其他資料。
HTTP之響應訊息Response
HTTP響應也由四個部分組成,分別是:狀態行、訊息報頭、空行和響應正文。
- 狀態行,由HTTP協議版本號, 狀態碼, 狀態訊息 三部分組成。
- 訊息報頭,用來說明客戶端要使用的一些附加資訊
- 第三部分:空行,訊息報頭後面的空行是必須的
- 第四部分:響應正文,伺服器返回給客戶端的文字資訊。
在瀏覽器位址列鍵入URL,按下回車之後會經歷以下流程:
- 瀏覽器向 DNS 伺服器請求解析該 URL 中的域名所對應的 IP 地址;
- 建立TCP連線;
- 瀏覽器發出讀取檔案(URL 中域名後面部分對應的檔案)的HTTP 請求,該請求報文作為 TCP 三次握手的第三個報文的資料傳送給伺服器;
- 伺服器對瀏覽器請求作出響應,並把對應的 html 文字傳送給瀏覽器;
- 釋放 TCP連線(四次揮手);
- 瀏覽器將該 html 文字並顯示內容;
三次握手
SYN (同步序列編號)ACK(確認字元)
- 第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client進入SYN_SENT狀態,等待Server確認。
- 第二次握手:Server收到資料包後由標誌位SYN=1知道Client請求建立連線,Server將標誌位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,並將該資料包傳送給Client以確認連線請求,Server進入SYN_RCVD狀態。
- 第三次握手:Client收到確認後,檢查ack是否為J+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=K+1,並將該資料包傳送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連線建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間可以開始傳輸資料了。
四次揮手
- 第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送,Client進入FIN_WAIT_1狀態。
- 第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。
- 第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送,Server進入LAST_ACK狀態。
- 第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接著傳送一個ACK給Server,確認序號為收到序號+1,Server進入CLOSED狀態,完成四次揮手。
為什麼建立連線是三次握手,而關閉連線卻是四次揮手呢?
這是因為服務端在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。而關閉連線時,當收到對方的FIN報文時,僅僅表示對方不再傳送資料了但是還能接收資料,己方也未必全部資料都傳送給對方了,所以己方可以立即close,也可以傳送一些資料給對方後,再傳送FIN報文給對方來表示同意現在關閉連線,因此,己方ACK和FIN一般都會分開傳送。
網頁生成的過程,大致可以分為五步:
- html程式碼轉化為dom
- css程式碼轉化為cssom
- 結合dom和cssom,生成一顆渲染樹
- 生成佈局layout,即將所有的渲染樹的節點進行平面合成
- 將佈局繪製paint在螢幕上(可以擴充講一下減少瀏覽器渲染的重排和重繪)
瀏覽器快取
當瀏覽器再次訪問一個已經訪問過的資源時,它會這樣做:
- 看看是否命中強快取,如果命中,就直接使用快取了。
- 如果沒有命中強快取,就發請求到伺服器檢查是否命中協商快取。
- 如果命中協商快取,伺服器會返回 304 告訴瀏覽器使用本地快取。
- 否則,返回最新的資源。
vue
vue Virtual DOM
其實 VNode 是對真實 DOM 的一種抽象描述,它的核心定義無非就幾個關鍵屬性,標籤名、資料、子節點、鍵值等,其它屬性都是都是用來擴充套件 VNode 的靈活性以及實現一些特殊 feature 的。由於 VNode 只是用來對映到真實 DOM 的渲染,不需要包含操作 DOM 的方法,因此它是非常輕量和簡單的。 Virtual DOM 除了它的資料結構的定義,對映到真實的 DOM 實際上要經歷 VNode 的 create、diff、patch 等過程。那麼在 Vue.js 中,VNode 的 create 是通過之前提到的 createElement 方法建立的,我們接下來分析這部分的實現。
vue的響應式原理
Object.defineProperty(obj, prop, descriptor)
- obj 是要在其上定義屬性的物件;prop 是要定義或修改的屬性的名稱;descriptor 是將被定義或修改的屬性描述符。 比較核心的是 descriptor,它有很多可選鍵值,具體的可以去參閱它的文件。這裡我們最關心的是 get 和 set,get 是一個給屬性提供的 getter 方法,當我們訪問了該屬性的時候會觸發 getter 方法;set 是一個給屬性提供的 setter 方法,當我們對該屬性做修改的時候會觸發 setter 方法。一旦物件擁有了 getter 和 setter,我們可以簡單地把這個物件稱為響應式物件
observe
- observe 方法的作用就是給非 VNode 的物件型別資料新增一個 Observer,如果已經新增過則直接返回,否則在滿足一定條件下去例項化一個 Observer 物件例項。
- observe 的功能就是用來監測資料的變化.
- Observer 是一個類,它的作用是給物件的屬性新增 getter 和 setter,用於依賴收集和派發更新:
- 依賴收集和派發更新
- 收集依賴的目的是為了當這些響應式資料發生變化,觸發它們的 setter 的時候,能知道應該通知哪些訂閱者去做相應的邏輯處理,我們把這個過程叫派發更新,其實 Watcher 和 Dep 就是一個非常經典的觀察者設計模式的實現
- 派發更新就是資料發生變化的時候,觸發 setter 邏輯,把在依賴過程中訂閱的的所有觀察者,也就是 watcher,都觸發它們的 update 過程,這個過程又利用了佇列做了進一步優化,在 nextTick 後執行所有 watcher 的 run,最後執行它們的回撥函式
vue編譯的過程主要分以下幾步
// 解析模板字串生成 AST
const ast = parse(template.trim(), options)
//優化語法樹
optimize(ast, options)
//生成程式碼
const code = generate(ast, options)
複製程式碼
對vuex的理解,單向資料流
前端安全
XSS和CSRF
- XSS:跨站指令碼攻擊,是一種網站應用程式的安全漏洞攻擊,是程式碼注入的一種。常見方式是將惡意程式碼注入合法程式碼裡隱藏起來,再誘發惡意程式碼,從而進行各種各樣的非法活動。
預防:
-
使用XSS Filter
- 輸入過濾,對使用者提交的資料進行有效性驗證,僅接受指定長度範圍內並符合我們期望格式的的內容提交,阻止或者忽略除此外的其他任何資料。
- 輸出轉義,當需要將一個字串輸出到Web網頁時,同時又不確定這個字串中是否包括XSS特殊字元,為了確保輸出內容的完整性和正確性,輸出HTML屬性時可以使用HTML轉義編碼(HTMLEncode)進行處理,輸出到
<script>
中,可以進行JS編碼。
-
使用 HttpOnly Cookie 將重要的cookie標記為httponly,這樣的話當瀏覽器向Web伺服器發起請求的時就會帶上cookie欄位,但是在js指令碼中卻不能訪問這個cookie,這樣就避免了XSS攻擊利用JavaScript的document.cookie獲取cookie。
-
CSRF:跨站請求偽造,也稱 XSRF,是一種挾制使用者在當前已登入的Web應用程式上執行非本意的操作的攻擊方法。與 XSS 相比,XSS利用的是使用者對指定網站的信任,CSRF利用的是網站對使用者網頁瀏覽器的信任。
- 預防:使用者操作限制——驗證碼機制
- 方法:新增驗證碼來識別是不是使用者主動去發起這個請求,由於一定強度的驗證碼機器無法識別,因此危險網站不能偽造一個完整的請求。
- 優點:簡單粗暴,低成本,可靠,能防範99.99%的攻擊者。
- 缺點:對使用者不友好。
- 請求來源限制——驗證 HTTP Referer 欄位
- 方法:在HTTP請求頭中有一個欄位叫Referer,它記錄了請求的來源地址。 伺服器需要做的是驗證這個來源地址是否合法,如果是來自一些不受信任的網站,則拒絕響應。
- 優點:零成本,簡單易實現。
- 缺點:由於這個方法嚴重依賴瀏覽器自身,因此安全性全看瀏覽器。
- 額外驗證機制——token的使用
- 方法:使用token來代替驗證碼驗證。由於黑客並不能拿到和看到cookie裡的內容,所以無法偽造一個完整的請求。基本思路如下:
- 伺服器隨機產生token(比如把cookie hash化生成),存在session中,放在cookie中或者以ajax的形式交給前端。
- 前端發請求的時候,解析cookie中的token,放到請求url裡或者請求頭中。
- 伺服器驗證token,由於黑客無法得到或者偽造token,所以能防範csrf