摘要:狀態(tài)行,由協(xié)議版本號(hào),狀態(tài)碼,狀態(tài)消息三部分組成。第四次揮手收到后,進(jìn)入狀態(tài),接著發(fā)送一個(gè)給,確認(rèn)序號(hào)為收到序號(hào),進(jìn)入狀態(tài),完成四次揮手。否則,返回最新的資源。
題庫長期更新維護(hù) css部分 rem原理
rem布局的本質(zhì)是等比縮放,一般是基于寬度,假設(shè)將屏幕寬度分為100份,每份寬度是1rem,1rem的寬度是屏幕寬度/100,,然后子元素設(shè)置rem單位的屬性,
通過改變html元素的字體大小,就可以設(shè)置子元素的實(shí)際大小。
rem布局加載閃爍的問題
解決方案,媒體查詢?cè)O(shè)置根元素字體大小,比如設(shè)計(jì)稿是750px;對(duì)應(yīng)的開發(fā)方式是1rem=100px,那375px的font-size 大小就是50px(具體方法可以百度一下)
比rem更好的方案(缺點(diǎn)兼容不好)
vw(1vw是視口寬度的1%,100vw就是視口寬度),vh(100vh就是視口高度)
實(shí)現(xiàn)三欄布局(兩側(cè)定寬,中間自適應(yīng))采用了 absolute,導(dǎo)致父元素脫離了文檔流,那所有的子元素也需要脫離文檔流。如果頁面復(fù)雜,那開發(fā)的難度可想而知
利用浮動(dòng) 當(dāng)中間內(nèi)容高于兩側(cè)時(shí),兩側(cè)高度不會(huì)隨中間內(nèi)容變高而變高
彈性盒子布局(flex)
利用負(fù)邊距和浮動(dòng),實(shí)現(xiàn)起來比較復(fù)雜
利用網(wǎng)格布局
.container { display: grid; grid-template-columns: 100px auto 200px; }BFC(塊級(jí)格式化上下文)
BFC 的原理
其實(shí)也就是 BFC 的渲染規(guī)則(能說出以下四點(diǎn)就夠了)。包括:
1. BFC 內(nèi)部的子元素,在垂直方向,邊距會(huì)發(fā)生重疊。 2. BFC在頁面中是獨(dú)立的容器,外面的元素不會(huì)影響里面的元素,反之亦然。 3. BFC區(qū)域不與旁邊的float box區(qū)域重疊。(可以用來清除浮動(dòng)帶來的影響)。 4. 計(jì)算BFC的高度時(shí),浮動(dòng)的子元素也參與計(jì)算。
如何生成BFC
方法1:overflow: 不為visible,可以讓屬性是 hidden、auto。【最常用】
方法2:浮動(dòng)中:float的屬性值不為none。意思是,只要設(shè)置了浮動(dòng),當(dāng)前元素就創(chuàng)建了BFC。
方法3:定位中:只要posiiton的值不是 static或者是relative即可,可以是absolute或fixed,也就生成了一個(gè)BFC。
方法4:display為inline-block, table-cell, table-caption, flex, inline-flex
BFC應(yīng)用
阻止margin重疊
可以包含浮動(dòng)元素 —— 清除內(nèi)部浮動(dòng)(清除浮動(dòng)的原理是兩個(gè)div都位于同一個(gè) BFC 區(qū)域之中)
自適應(yīng)兩欄布局
可以阻止元素被浮動(dòng)元素覆蓋
flex(面試常問,略) js部分 call, apply, bind區(qū)別? 怎么實(shí)現(xiàn)call,apply方法Function.prototype.myBind = function(content) { if(type of this !="function"){ throw Error("not a function") } let _this = this; let args = [...arguments].slice(1) let resFn=function(){ return _this.apply(this instanceof resFn?this:content,content.concat(...arguments)) } return resFn }; /** * 每個(gè)函數(shù)都可以調(diào)用call方法,來改變當(dāng)前這個(gè)函數(shù)執(zhí)行的this關(guān)鍵字,并且支持傳入?yún)?shù) */ Function.prototype.myCall=function(context=window){ context.fn = this;//此處this是指調(diào)用myCall的function let args=[...arguments].slice(1); let result=content.fn(...args) //將this指向銷毀 delete context.fn; return result; } /** * apply函數(shù)傳入的是this指向和參數(shù)數(shù)組 */ Function.prototype.myApply = function(context=window) { context.fn = this; let result; if(arguments[1]){ result=context.fn(...arguments[1]) }else{ result=context.fn() } //將this指向銷毀 delete context.fn; return result; }函數(shù)柯里化 js繼承,構(gòu)造函數(shù),原型鏈,構(gòu)造函數(shù)、原型鏈組合式繼承,寄生式組合繼承,Object.create polyfill; 數(shù)組去重
[...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防抖節(jié)流
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 > prev + wait) { prev = now; fn.apply(this, args) } } }實(shí)現(xiàn)Promise思路
//0 pending,1 resolve,2 reject function Promise(fn) {... this._state = 0 // 狀態(tài)標(biāo)記 doResolve(fn, this) } function doResolve(fn, self) { var done = false // 保證只執(zhí)行一個(gè)監(jiān)聽 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); } }實(shí)現(xiàn)深拷貝
funtion deepCopy(obj){ let result; if(typeofObj=="object"){ //復(fù)雜數(shù)據(jù)類型 result=obj.constructor==Array?[]:{} for (let i in obj){ result[i]=typeof obj[i]=="object"?deepCopy(obj[i]):obj[i] } }else{ //簡(jiǎn)單數(shù)據(jù)類型 result=obj } return result }正則實(shí)現(xiàn)千位分隔符
function commafy(num) { return num && num .toString() .replace(/(d)(?=(d{3})+.)/g, function($0, $1) { return $1 + ","; }); } console.log(commafy(1312567.903000))js事件循環(huán)
javascript是單線程語言,任務(wù)設(shè)計(jì)成了兩類,同步任務(wù)和異步任務(wù)
同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行“場(chǎng)所”,同步進(jìn)入主線程,異步進(jìn)入Event Table并注冊(cè)函數(shù)。當(dāng)指定的事情完成時(shí),Event Table會(huì)將這個(gè)函數(shù)移入Event Queue。主線程內(nèi)的任務(wù)執(zhí)行完畢為空,回去了Event Queue讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線程。
上述過程會(huì)不斷重復(fù),也就是常說的Event Loop(事件循環(huán))。
但是,JS異步還有一個(gè)機(jī)制,就是遇到宏任務(wù),先執(zhí)行宏任務(wù),將宏任務(wù)放入event queue,然后再執(zhí)行微任務(wù),將微任務(wù)放入eventqueue,但是,這兩個(gè)queue不是一個(gè)queue。當(dāng)你往外拿的時(shí)候先從微任務(wù)里拿這個(gè)回調(diào)函數(shù),然后再從宏任務(wù)的queue拿宏任務(wù)的回調(diào)函數(shù)
宏任務(wù)一般包括:整體代碼script,setTimeout,setInterval。
微任務(wù):Promise,process.nextTick
事件捕獲
處于目標(biāo)階段
事件冒泡階段
事件委托 事件委托是指將事件綁定目標(biāo)元素的到父元素上,利用冒泡機(jī)制觸發(fā)該事件
可以減少事件注冊(cè),節(jié)省大量內(nèi)存占用可以將事件應(yīng)用于動(dòng)態(tài)添加的子元素上
event.target返回觸發(fā)事件的元素
event.currentTarget返回綁定事件的元素
new的過程以及實(shí)現(xiàn)new//方法1 function create(){ //1.創(chuàng)建一個(gè)空對(duì)象 let obj={} //2.獲取構(gòu)造函數(shù) let Con=[].shift.call(arguments) //3.設(shè)置空對(duì)象的原型 obj._proto_=Con.prototype //4.綁定this并執(zhí)行構(gòu)造函數(shù),給新對(duì)象添加屬性和方法 let result=Con.apply(obj,arguments) //5.確保返回值為對(duì)象 return result instanceof Object?result:obj } //方法2 //通過分析原生的new方法可以看出,在new一個(gè)函數(shù)的時(shí)候, // 會(huì)返回一個(gè)func同時(shí)在這個(gè)func里面會(huì)返回一個(gè)對(duì)象Object, // 這個(gè)對(duì)象包含父類func的屬性以及隱藏的__proto__ function New(f) { //返回一個(gè)func return function () { var o = {"__proto__": f.prototype}; f.apply(o, arguments);//繼承父類的屬性 return o; //返回一個(gè)Object } }封裝ajax
/* 封裝ajax函數(shù) * @param {string}opt.type http連接的方式,包括POST和GET兩種方式 * @param {string}opt.url 發(fā)送請(qǐng)求的url * @param {boolean}opt.async 是否為異步請(qǐng)求,true為異步的,false為同步的 * @param {object}opt.data 發(fā)送的參數(shù),格式為對(duì)象類型 * @param {function}opt.success ajax發(fā)送并接收成功調(diào)用的回調(diào)函數(shù) */ 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數(shù)據(jù)可以在這使用opt.success(JSON.parse( xmlHttp.responseText)) } }; }url拿參數(shù)
var url = "http://www.taobao.com/index.php?key0=0&key1=1&key2=2"; function parseQueryString(url){ var str = url.split("?")[1], //通過?得到一個(gè)數(shù)組,取?后面的參數(shù) items = str.split("&"); //分割成數(shù)組 var arr,name,value; for(var i=0; iHTTP部分 http協(xié)議 HTTP協(xié)議(超文本傳輸協(xié)議)
1.0 協(xié)議缺陷:
無法復(fù)用鏈接,完成即斷開,重新慢啟動(dòng)和 TCP 3次握手
head of line blocking: 線頭阻塞,導(dǎo)致請(qǐng)求之間互相影響
1.1 改進(jìn):
長連接(默認(rèn) keep-alive),復(fù)用
host 字段指定對(duì)應(yīng)的虛擬站點(diǎn)
新增功能:
斷點(diǎn)續(xù)傳
身份認(rèn)證
狀態(tài)管理
cache 緩存
Cache-Control
Expires
Last-Modified
Etag
2.0:
多路復(fù)用
二進(jìn)制分幀層: 應(yīng)用層和傳輸層之間
首部壓縮
服務(wù)端推送
HTTP之請(qǐng)求消息Request
請(qǐng)求行(request line)、請(qǐng)求頭部(header)、空行和請(qǐng)求數(shù)據(jù)四個(gè)部分組成。
請(qǐng)求行,用來說明請(qǐng)求類型,要訪問的資源以及所使用的HTTP版本.
請(qǐng)求頭部,緊接著請(qǐng)求行(即第一行)之后的部分,用來說明服務(wù)器要使用的附加信息
空行,請(qǐng)求頭部后面的空行是必須的
請(qǐng)求數(shù)據(jù)也叫主體,可以添加任意的其他數(shù)據(jù)。
HTTP之響應(yīng)消息Response
HTTP響應(yīng)也由四個(gè)部分組成,分別是:狀態(tài)行、消息報(bào)頭、空行和響應(yīng)正文。
狀態(tài)行,由HTTP協(xié)議版本號(hào), 狀態(tài)碼, 狀態(tài)消息 三部分組成。
消息報(bào)頭,用來說明客戶端要使用的一些附加信息
第三部分:空行,消息報(bào)頭后面的空行是必須的
第四部分:響應(yīng)正文,服務(wù)器返回給客戶端的文本信息。
在瀏覽器地址欄鍵入U(xiǎn)RL,按下回車之后會(huì)經(jīng)歷以下流程:瀏覽器向 DNS 服務(wù)器請(qǐng)求解析該 URL 中的域名所對(duì)應(yīng)的 IP 地址;
建立TCP連接(三次握手);
瀏覽器發(fā)出讀取文件(URL 中域名后面部分對(duì)應(yīng)的文件)的HTTP 請(qǐng)求,該請(qǐng)求報(bào)文作為 TCP 三次握手的第三個(gè)報(bào)文的數(shù)據(jù)發(fā)送給服務(wù)器;
服務(wù)器對(duì)瀏覽器請(qǐng)求作出響應(yīng),并把對(duì)應(yīng)的 html 文本發(fā)送給瀏覽器;
釋放 TCP連接(四次揮手);
瀏覽器將該 html 文本并顯示內(nèi)容;
三次握手SYN (同步序列編號(hào))ACK(確認(rèn)字符)
第一次握手:Client將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個(gè)值seq=J,并將該數(shù)據(jù)包發(fā)送給Server,Client進(jìn)入SYN_SENT狀態(tài),等待Server確認(rèn)。
第二次握手:Server收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道Client請(qǐng)求建立連接,Server將標(biāo)志位SYN和ACK都置為1,ack=J+1,隨機(jī)產(chǎn)生一個(gè)值seq=K,并將該數(shù)據(jù)包發(fā)送給Client以確認(rèn)連接請(qǐng)求,Server進(jìn)入SYN_RCVD狀態(tài)。
第三次握手:Client收到確認(rèn)后,檢查ack是否為J+1,ACK是否為1,如果正確則將標(biāo)志位ACK置為1,ack=K+1,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進(jìn)入ESTABLISHED狀態(tài),完成三次握手,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了。
四次揮手第一次揮手:Client發(fā)送一個(gè)FIN,用來關(guān)閉Client到Server的數(shù)據(jù)傳送,Client進(jìn)入FIN_WAIT_1狀態(tài)。
第二次揮手:Server收到FIN后,發(fā)送一個(gè)ACK給Client,確認(rèn)序號(hào)為收到序號(hào)+1(與SYN相同,一個(gè)FIN占用一個(gè)序號(hào)),Server進(jìn)入CLOSE_WAIT狀態(tài)。
第三次揮手:Server發(fā)送一個(gè)FIN,用來關(guān)閉Server到Client的數(shù)據(jù)傳送,Server進(jìn)入LAST_ACK狀態(tài)。
第四次揮手:Client收到FIN后,Client進(jìn)入TIME_WAIT狀態(tài),接著發(fā)送一個(gè)ACK給Server,確認(rèn)序號(hào)為收到序號(hào)+1,Server進(jìn)入CLOSED狀態(tài),完成四次揮手。
為什么建立連接是三次握手,而關(guān)閉連接卻是四次揮手呢?這是因?yàn)榉?wù)端在LISTEN狀態(tài)下,收到建立連接請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。而關(guān)閉連接時(shí),當(dāng)收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),己方也未必全部數(shù)據(jù)都發(fā)送給對(duì)方了,所以己方可以立即close,也可以發(fā)送一些數(shù)據(jù)給對(duì)方后,再發(fā)送FIN報(bào)文給對(duì)方來表示同意現(xiàn)在關(guān)閉連接,因此,己方ACK和FIN一般都會(huì)分開發(fā)送。
網(wǎng)頁生成的過程,大致可以分為五步:html代碼轉(zhuǎn)化為dom
css代碼轉(zhuǎn)化為cssom
結(jié)合dom和cssom,生成一顆渲染樹
生成布局layout,即將所有的渲染樹的節(jié)點(diǎn)進(jìn)行平面合成
將布局繪制paint在屏幕上(可以拓展講一下減少瀏覽器渲染的回流和重繪)
HTTPS的工作原理非對(duì)稱加密與對(duì)稱加密雙劍合璧,使用非對(duì)稱加密算法傳遞用于對(duì)稱加密算法的密鑰,然后使用對(duì)稱加密算法進(jìn)行信息傳遞。這樣既安全又高效
瀏覽器緩存當(dāng)瀏覽器再次訪問一個(gè)已經(jīng)訪問過的資源時(shí),它會(huì)這樣做:
看看是否命中強(qiáng)緩存,如果命中,就直接使用緩存了。
如果沒有命中強(qiáng)緩存,就發(fā)請(qǐng)求到服務(wù)器檢查是否命中協(xié)商緩存。
如果命中協(xié)商緩存,服務(wù)器會(huì)返回 304 告訴瀏覽器使用本地緩存。
否則,返回最新的資源。
強(qiáng)緩存
Expires
Cache-control
協(xié)商緩存
Last-Modified/If-Modified-Since
Etag/If-None-Match
vue&react Virtual DOM其實(shí) VNode 是對(duì)真實(shí) DOM 的一種抽象描述,它的核心定義無非就幾個(gè)關(guān)鍵屬性,標(biāo)簽名、數(shù)據(jù)、子節(jié)點(diǎn)、鍵值等,其它屬性都是都是用來擴(kuò)展 VNode 的靈活性以及實(shí)現(xiàn)一些特殊 feature 的。由于 VNode 只是用來映射到真實(shí) DOM 的渲染,不需要包含操作 DOM 的方法,因此它是非常輕量和簡(jiǎn)單的。
diff算法
Virtual DOM 除了它的數(shù)據(jù)結(jié)構(gòu)的定義,映射到真實(shí)的 DOM 實(shí)際上要經(jīng)歷 VNode 的 create(用JS對(duì)象模擬DOM樹)、diff(比較兩棵虛擬DOM樹的差異)、patch(把差異應(yīng)用到真正的DOM樹上) 等過程。diff算法比較新舊節(jié)點(diǎn)的時(shí)候,比較只會(huì)在同層級(jí)比較,不會(huì)跨層級(jí)比較
當(dāng)數(shù)據(jù)發(fā)生變化的時(shí)候會(huì)生成一個(gè)新的VNode,然后新VNode和oldNode做對(duì)比,發(fā)現(xiàn)不一樣的地方直接修改在真實(shí)的dom上,比較新舊節(jié)點(diǎn),一邊比較一邊給真是的dom打補(bǔ)丁
節(jié)點(diǎn)設(shè)置key可以高效的利用dom(key最好不要設(shè)置成index索引)
虛擬DOM diff算法主要就是對(duì)以下三種場(chǎng)景進(jìn)行優(yōu)化:
tree diff
對(duì)樹進(jìn)行分層比較,兩棵樹只會(huì)對(duì)同一層次的節(jié)點(diǎn)進(jìn)行比較。(因?yàn)?DOM 節(jié)點(diǎn)跨層級(jí)的移動(dòng)操作少到可以忽略不計(jì))
如果父節(jié)點(diǎn)已經(jīng)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉,不會(huì)用于進(jìn)一步的比較。
注意:
React 官方建議不要進(jìn)行 DOM 節(jié)點(diǎn)跨層級(jí)的操作,非常影響 React 性能。
在開發(fā)組件時(shí),保持穩(wěn)定的 DOM 結(jié)構(gòu)會(huì)有助于性能的提升。例如,可以通過 CSS 隱藏或顯示節(jié)點(diǎn),而不是真的移除或添加 DOM 節(jié)點(diǎn)。component diff
如果是同一類型的組件,按照原策略繼續(xù)比較 virtual DOM tree(tree diff)。
對(duì)于同一類型的組件,有可能其 Virtual DOM 沒有任何變化,如果能夠確切的知道這點(diǎn)那可以節(jié)省大量的 diff 運(yùn)算時(shí)間,因此 React 允許用戶通過 shouldComponentUpdate() 來判斷該組件是否需要進(jìn)行 diff。
如果不是,直接替換整個(gè)組件下的所有子節(jié)點(diǎn)。element diff
對(duì)處于同一層級(jí)的節(jié)點(diǎn)進(jìn)行對(duì)比。
vue的響應(yīng)式原理
這時(shí) React 建議:添加唯一 key 進(jìn)行區(qū)分。雖然只是小小的改動(dòng),性能上卻發(fā)生了翻天覆地的變化!
如: A B C D --> B A D C
添加 key 之前: 發(fā)現(xiàn) B != A,則創(chuàng)建并插入 B 至新集合,刪除老集合 A;以此類推,創(chuàng)建并插入 A、D 和 C,刪除 B、C 和 D。
添加 key 之后: B、D 不做任何操作,A、C 進(jìn)行移動(dòng)操作,即可。
建議:在開發(fā)過程中,盡量減少類似將最后一個(gè)節(jié)點(diǎn)移動(dòng)到列表首部的操作,當(dāng)節(jié)點(diǎn)數(shù)量過大或更新操作過于頻繁時(shí),在一定程度上會(huì)影響 React 的渲染性能。
Object.defineProperty(obj, prop, descriptor)
obj 是要在其上定義屬性的對(duì)象;prop 是要定義或修改的屬性的名稱;descriptor 是將被定義或修改的屬性描述符。
比較核心的是 descriptor,它有很多可選鍵值,具體的可以去參閱它的文檔。這里我們最關(guān)心的是 get 和 set,get 是一個(gè)給屬性提供的 getter 方法,當(dāng)我們?cè)L問了該屬性的時(shí)候會(huì)觸發(fā) getter 方法;set 是一個(gè)給屬性提供的 setter 方法,當(dāng)我們對(duì)該屬性做修改的時(shí)候會(huì)觸發(fā) setter 方法。一旦對(duì)象擁有了 getter 和 setter,我們可以簡(jiǎn)單地把這個(gè)對(duì)象稱為響應(yīng)式對(duì)象
- 對(duì)象遞歸調(diào)用 - 數(shù)組變異方法的解決方法:代理原型/實(shí)例方法
observe
observe 方法的作用就是給非 VNode 的對(duì)象類型數(shù)據(jù)添加一個(gè) Observer,如果已經(jīng)添加過則直接返回,否則在滿足一定條件下去實(shí)例化一個(gè) Observer 對(duì)象實(shí)例。
observe 的功能就是用來監(jiān)測(cè)數(shù)據(jù)的變化.
Observer 是一個(gè)類,它的作用是給對(duì)象的屬性添加 getter 和 setter,用于依賴收集和派發(fā)更新:
依賴收集和派發(fā)更新
收集依賴的目的是為了當(dāng)這些響應(yīng)式數(shù)據(jù)發(fā)生變化,觸發(fā)它們的 setter 的時(shí)候,能知道應(yīng)該通知哪些訂閱者去做相應(yīng)的邏輯處理,我們把這個(gè)過程叫派發(fā)更新,其實(shí) Watcher 和 Dep 就是一個(gè)非常經(jīng)典的觀察者設(shè)計(jì)模式的實(shí)現(xiàn)
派發(fā)更新就是數(shù)據(jù)發(fā)生變化的時(shí)候,觸發(fā) setter 邏輯,把在依賴過程中訂閱的的所有觀察者,也就是 watcher,都觸發(fā)它們的 update 過程,這個(gè)過程又利用了隊(duì)列做了進(jìn)一步優(yōu)化,在 nextTick 后執(zhí)行所有 watcher 的 run,最后執(zhí)行它們的回調(diào)函數(shù)
vue編譯Compile的過程主要分以下幾步
parse(生成AST)=> optimize(優(yōu)化靜態(tài)節(jié)點(diǎn)) => generate(生成render function)
// 解析模板字符串生成 AST const ast = parse(template.trim(), options) //優(yōu)化語法樹 optimize(ast, options) //生成代碼 const code = generate(ast, options)vue compute和watch的區(qū)別computed 是計(jì)算屬性,依賴其他屬性計(jì)算值,并且 computed 的值有緩存,只有當(dāng)計(jì)算值變化才會(huì)返回內(nèi)容。
watch 監(jiān)聽到值的變化就會(huì)執(zhí)行回調(diào),在回調(diào)中可以進(jìn)行一些邏輯操作。
所以一般來說需要依賴別的屬性來動(dòng)態(tài)獲得值的時(shí)候可以使用computed,對(duì)于監(jiān)聽到值的變化需要做一些復(fù)雜業(yè)務(wù)邏輯的情況可以使用 watch。
對(duì)vuex的理解,單向數(shù)據(jù)流vuex
state: 狀態(tài)中心
mutations: 更改狀態(tài)
actions: 異步更改狀態(tài)
getters: 獲取狀態(tài)
modules: 將state分成多個(gè)modules,便于管理
mutations和action的區(qū)別
前端路由的兩種實(shí)現(xiàn)原理
Hash模式
window對(duì)象提供了onhashchange事件來監(jiān)聽hash值的改變,一旦url中的hash值發(fā)生改變,便會(huì)觸發(fā)該事件。
History 模式
popstate監(jiān)聽歷史棧信息變化,變化時(shí)重新渲染
使用pushState方法實(shí)現(xiàn)添加功能
使用replaceState實(shí)現(xiàn)替換功能
前端安全 XSS和CSRFXSS:跨站腳本攻擊,是一種網(wǎng)站應(yīng)用程序的安全漏洞攻擊,是代碼注入的一種。常見方式是將惡意代碼注入合法代碼里隱藏起來,再誘發(fā)惡意代碼,從而進(jìn)行各種各樣的非法活動(dòng)。
預(yù)防:
使用XSS Filter
輸入過濾,對(duì)用戶提交的數(shù)據(jù)進(jìn)行有效性驗(yàn)證,僅接受指定長度范圍內(nèi)并符合我們期望格式的的內(nèi)容提交,阻止或者忽略除此外的其他任何數(shù)據(jù)。
輸出轉(zhuǎn)義,當(dāng)需要將一個(gè)字符串輸出到Web網(wǎng)頁時(shí),同時(shí)又不確定這個(gè)字符串中是否包括XSS特殊字符,為了確保輸出內(nèi)容的完整性和正確性,輸出HTML屬性時(shí)可以使用HTML轉(zhuǎn)義編碼(HTMLEncode)進(jìn)行處理,輸出到
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/109325.html
摘要:在盒模型中,設(shè)置的是的寬度高度,在怪異模式中設(shè)置的是寬度高度。狀態(tài)行,由協(xié)議版本號(hào),狀態(tài)碼,狀態(tài)消息三部分組成。第四次揮手收到后,進(jìn)入狀態(tài),接著發(fā)送一個(gè)給,確認(rèn)序號(hào)為收到序號(hào),進(jìn)入狀態(tài),完成四次揮手。評(píng)論區(qū)可以糾錯(cuò)完善,也可以留言面試題目 css部分 rem原理 rem布局的本質(zhì)是等比縮放,一般是基于寬度,假設(shè)將屏幕寬度分為100份,每份寬度是1rem,1rem的寬度是屏幕寬度/100,,...
摘要:獲取的對(duì)象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對(duì)象即使沒有代碼,也會(huì)把默認(rèn)的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對(duì)于一個(gè)光禿禿的元素,方法返回對(duì)象中屬性值如果有就是據(jù)我測(cè)試不同環(huán)境結(jié)果可能有差異而就是。 花了很長時(shí)間整理的前端面試資源,喜歡請(qǐng)大家不要吝嗇star~ 別只收藏,點(diǎn)個(gè)贊,點(diǎn)個(gè)star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項(xiàng)目地址 https:...
摘要:三年百度,五年阿里,阿里架構(gòu)師淺談我是如何順利進(jìn)入前些天在我群里認(rèn)識(shí)了以為挺有意思的老哥,他也是工作年多技術(shù)和面試都不差,最近也是在找工作,是從京城來魔都的,也和他撈了不少。 說來慚愧,也不怕你們笑話。做開發(fā)8年多,到目前還是一名不折不扣的掃地僧。年前的辭職,到現(xiàn)在還在家靜養(yǎng)中。其實(shí)也沒什么,就是回家總結(jié)一下自己這些年來在外工作與面試等做一個(gè)簡(jiǎn)單的總結(jié)與反思。做一下自己后面一個(gè)人生規(guī)劃...
閱讀 2624·2021-11-22 09:34
閱讀 3602·2021-11-15 11:37
閱讀 2424·2021-09-13 10:37
閱讀 2181·2021-09-04 16:40
閱讀 1789·2021-09-02 15:40
閱讀 2516·2019-08-30 13:14
閱讀 3392·2019-08-29 13:42
閱讀 2006·2019-08-29 13:02