摘要:事件模型事件捕獲階段。事件到達(dá)目標(biāo)元素觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。的狀態(tài)值與狀態(tài)碼的狀態(tài)值未初始化還沒有調(diào)用方法。載入完成已經(jīng)執(zhí)行完成,已經(jīng)接收到全部的響應(yīng)內(nèi)容。
前言
總括: 包含這三個(gè)月來碰到的一些覺得比較好的面試題,三個(gè)月沒怎么寫博客著實(shí)有些手癢,哈哈哈。7000余字,不成敬意2333
原文地址:我的前端進(jìn)階之路
知乎專欄&&簡書專題:前端進(jìn)擊者(知乎)&&前端進(jìn)擊者(簡書)
博主博客地址:Damonare的個(gè)人博客
烈火試真金,逆境試強(qiáng)者
正文 React和Vue對(duì)比相同點(diǎn):
數(shù)據(jù)驅(qū)動(dòng)視圖,提供響應(yīng)式的視圖組件
都有Virtual DOM,組件化開發(fā),通過props參數(shù)進(jìn)行父子組件數(shù)據(jù)的傳遞,都實(shí)現(xiàn)webComponents規(guī)范
數(shù)據(jù)流動(dòng)單向
都支持服務(wù)端渲染
都有支持native的方案,React的React native,Vue的weex
不同點(diǎn):
社區(qū):React社區(qū)還是要比vue大很多;
開發(fā)模式:React在view層侵入性還是要比Vue大很多的,React嚴(yán)格上只針對(duì)MVC的view層,Vue則是MVVM模式的一種實(shí)現(xiàn);
數(shù)據(jù)綁定:Vue有實(shí)現(xiàn)了雙向數(shù)據(jù)綁定,React數(shù)據(jù)流動(dòng)是單向的
數(shù)據(jù)渲染:對(duì)于大規(guī)模數(shù)據(jù)渲染,React要比Vue更快,渲染機(jī)制啟動(dòng)時(shí)候要做的工作比較多;
數(shù)據(jù)更新方面:Vue 由于采用依賴追蹤,默認(rèn)就是優(yōu)化狀態(tài):你動(dòng)了多少數(shù)據(jù),就觸發(fā)多少更新,不多也不少。React在復(fù)雜的應(yīng)用里有兩個(gè)選擇:
(1). 手動(dòng)添加 shouldComponentUpdate 來避免不需要的 vdom re-render。 (2).Components 盡可能都用 pureRenderMixin,然后采用 redux 結(jié)構(gòu) + Immutable.js;
開發(fā)風(fēng)格的偏好:React 推薦的做法是 JSX + inline style,也就是把 HTML 和 CSS 全都寫進(jìn) JavaScript 了,即"all in js";Vue進(jìn)階之后推薦的是使用 webpack + vue-loader 的單文件組件格式,即html,css,js寫在同一個(gè)文件;
使用場景:React配合Redux架構(gòu)適合超大規(guī)模多人協(xié)作的復(fù)雜項(xiàng)目;Vue則適合小快靈的項(xiàng)目。對(duì)于需要對(duì) DOM 進(jìn)行很多自定義操作的項(xiàng)目,Vue 的靈活性優(yōu)于 React;
Vue要比React更好上手,具體可能體現(xiàn)在很多人不熟悉React的JSX語法和函數(shù)式編程的思想,以及想要發(fā)揮出React的最大威力需要學(xué)習(xí)它一系列生態(tài)的緣故;
Vue著重提高開發(fā)效率,讓前端程序員更快速方便的開發(fā)應(yīng)用。React著重于變革開發(fā)思想,提升前端程序員編程的深度與創(chuàng)造力,讓前端工程師成為真正的程序員而不是UI的構(gòu)建者;
gulp和webpack區(qū)別gulp是一種工具,我們可以用它來優(yōu)化前端的工作流程,比如自動(dòng)刷新頁面、combo、壓縮css、js、編譯less等等。具體體現(xiàn)為:在gulp的配置文件中書寫一個(gè)個(gè)的task,webpack則是一種打包工具,或者說是一種模塊化解決方案,實(shí)際上很大一部分人剛開始使用webpack的方式就是通過gulp-webpack這個(gè)插件,寫好task來使用webpack對(duì)前端的一些文件進(jìn)行打包;
gulp的處理任務(wù)需要自己去寫,webpack則有現(xiàn)成的解決方案,只需要在webpack.config.js配置好即可;
防止重復(fù)發(fā)送Ajax請(qǐng)求用戶點(diǎn)擊之后按鈕disabled;
函數(shù)節(jié)流
abort掉上一個(gè)請(qǐng)求。
事件模型事件捕獲階段(capturing phase)。事件從document一直向下傳播到目標(biāo)元素, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件處理階段(target phase)。事件到達(dá)目標(biāo)元素, 觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標(biāo)元素冒泡到document, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
瀏覽器緩存機(jī)制Expires策略
Expires是Web服務(wù)器響應(yīng)消息頭字段,在響應(yīng)http請(qǐng)求時(shí)告訴瀏覽器在過期時(shí)間前瀏覽器可以直接從瀏覽器緩存取數(shù)據(jù),而無需再次請(qǐng)求。Expires 是HTTP 1.0的東西,現(xiàn)在默認(rèn)瀏覽器均默認(rèn)使用HTTP 1.1,所以它的作用基本忽略。
Cache-Control策略
Cache-Control與Expires的作用一致,都是指明當(dāng)前資源的有效期,控制瀏覽器是否直接從瀏覽器緩讀取數(shù)據(jù)還是重新發(fā)請(qǐng)求到服務(wù)器取數(shù)據(jù)。只不過Cache-Control的選擇更多,設(shè)置更細(xì)致,如果同時(shí)設(shè)置的話,其優(yōu)先級(jí)高于Expires。
以上是設(shè)置緩存時(shí)間的兩種方法。那么當(dāng)緩存時(shí)間過了咋整呢?有人肯定說了,那就再次發(fā)起請(qǐng)求啊,這是對(duì)的。問題是如果服務(wù)器資源并沒有更新呢?比如說我有一個(gè)jQuery.js文件已經(jīng)緩存了,當(dāng)它的緩存時(shí)間到了之后服務(wù)器的jQuery.js文件也沒有更新,那實(shí)際上我們直接使用本地緩存的文件就可以啊!沒必要浪費(fèi)帶寬和時(shí)間去重新請(qǐng)求一個(gè)新的文件啊!這時(shí)候我們就需要再進(jìn)一步看一下HTTP協(xié)議里這幾個(gè)參數(shù)的作用了。
Last-Modified/If-Modified-Since
首先Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified:標(biāo)示這個(gè)響應(yīng)資源的最后修改時(shí)間。web服務(wù)器在響應(yīng)請(qǐng)求時(shí),告訴瀏覽器資源的最后修改時(shí)間(這個(gè)參數(shù)是和Cache-Control一起過來的)。
If-Modified-Since:當(dāng)資源過期時(shí)(使用Cache-Control標(biāo)識(shí)的max-age),發(fā)現(xiàn)資源具有Last-Modified聲明,則再次向web服務(wù)器請(qǐng)求時(shí)帶上頭 If-Modified-Since,表示請(qǐng)求時(shí)間。web服務(wù)器收到請(qǐng)求后發(fā)現(xiàn)有頭If-Modified-Since ,則與被請(qǐng)求資源的最后修改時(shí)間進(jìn)行比對(duì)。若最后修改時(shí)間較新,說明資源又被改動(dòng)過,則響應(yīng)整片資源內(nèi)容(寫在響應(yīng)消息包體內(nèi)),HTTP 200;若最后修改時(shí)間較舊,說明資源無新修改,則響應(yīng)HTTP 304 (無需包體,節(jié)省瀏覽),告知瀏覽器繼續(xù)使用所保存的cache。
ETag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服務(wù)器響應(yīng)請(qǐng)求時(shí),告訴瀏覽器當(dāng)前資源在服務(wù)器的唯一標(biāo)識(shí)(生成規(guī)則由服務(wù)器覺得)。Apache中,ETag的值,默認(rèn)是對(duì)文件的索引節(jié)(INode),大小(Size)和最后修改時(shí)間(MTime)進(jìn)行Hash后得到的。
If-None-Match:當(dāng)資源過期時(shí)(使用Cache-Control標(biāo)識(shí)的max-age),發(fā)現(xiàn)資源具有Etage聲明,則再次向web服務(wù)器請(qǐng)求時(shí)帶上頭If-None-Match(Etag的值)。web服務(wù)器收到請(qǐng)求后發(fā)現(xiàn)有頭If-None-Match 則與被請(qǐng)求資源的相應(yīng)校驗(yàn)串進(jìn)行比對(duì),決定返回200或304。
ETag和Last-Modified
HTTP1.1中Etag的出現(xiàn)主要是為了解決幾個(gè)Last-Modified比較難解決的問題:
Last-Modified標(biāo)注的最后修改只能精確到秒級(jí),如果某些文件在1秒鐘以內(nèi),被修改多次的話,它將不能準(zhǔn)確標(biāo)注文件的修改時(shí)間
如果某些文件會(huì)被定期生成,當(dāng)有時(shí)內(nèi)容并沒有任何變化,但Last-Modified卻改變了,導(dǎo)致文件沒法使用緩存
有可能存在服務(wù)器沒有準(zhǔn)確獲取文件修改時(shí)間,或者與代理服務(wù)器時(shí)間不一致等情形
Etag是服務(wù)器自動(dòng)生成或者由開發(fā)者生成的對(duì)應(yīng)資源在服務(wù)器端的唯一標(biāo)識(shí)符,能夠更加準(zhǔn)確的控制緩存。Last-Modified與ETag是可以一起使用的,服務(wù)器會(huì)優(yōu)先驗(yàn)證ETag,一致的情況下,才會(huì)繼續(xù)比對(duì)Last-Modified,最后才決定是否返回304。
Ajax的狀態(tài)值與HTTP狀態(tài)碼Ajax的狀態(tài)值
0: (未初始化)還沒有調(diào)用send()方法。
1: (載入)已經(jīng)調(diào)用send()方法,正在派發(fā)請(qǐng)求。
2: (載入完成)send()已經(jīng)執(zhí)行完成,已經(jīng)接收到全部的響應(yīng)內(nèi)容。
3: (交互)正在解析響應(yīng)內(nèi)容。
4: (完成)響應(yīng)內(nèi)容已經(jīng)解析完成,用戶可以調(diào)用。
HTTP狀態(tài)碼
200 & OK: 請(qǐng)求成功;
204 & No Content: 請(qǐng)求處理成功,但沒有資源可以返回;
206 & Partial Content: 對(duì)資源某一部分進(jìn)行請(qǐng)求(比如對(duì)于只加載了一般的圖片剩余部分的請(qǐng)求);
301 & Move Permanently: 永久性重定向;
302 & Found: 臨時(shí)性重定向;
303 & See Other: 請(qǐng)求資源存在另一個(gè)URI,應(yīng)使用get方法請(qǐng)求;
304 & Not Modified: 服務(wù)器判斷本地緩存未更新,可以直接使用本地的緩存;
307 & Temporary Redirect: 臨時(shí)重定向;
400 & Bad Request: 請(qǐng)求報(bào)文存在語法錯(cuò)誤;
401 & Unauthorized: 請(qǐng)求需要通過HTTP認(rèn)證;
403 & Forbidden: 請(qǐng)求資源被服務(wù)器拒絕,訪問權(quán)限的問題;
404 & Not Found: 服務(wù)器上沒有請(qǐng)求的資源;
500 & Internal Server Error: 服務(wù)器執(zhí)行請(qǐng)求時(shí)出現(xiàn)錯(cuò)誤;
502 & Bad Gateway: 錯(cuò)誤的網(wǎng)關(guān);
503 & Service Unavailable: 服務(wù)器超載或正在維護(hù),無法處理請(qǐng)求;
504 & Gateway timeout: 網(wǎng)關(guān)超時(shí);
React-router原理1.History
老瀏覽器的history: 主要通過hash來實(shí)現(xiàn),對(duì)應(yīng)createHashHistory
高版本瀏覽器: 通過html5里面的history,對(duì)應(yīng)createBrowserHistory
node環(huán)境下: 主要存儲(chǔ)在memeory里面,對(duì)應(yīng)createMemoryHistory
內(nèi)部createHistory實(shí)現(xiàn):
// 內(nèi)部的抽象實(shí)現(xiàn) function createHistory(options={}) { ... return { listenBefore, // 內(nèi)部的hook機(jī)制,可以在location發(fā)生變化前執(zhí)行某些行為,AOP的實(shí)現(xiàn) listen, // location發(fā)生改變時(shí)觸發(fā)回調(diào) transitionTo, // 執(zhí)行l(wèi)ocation的改變 push, // 改變location replace, go, goBack, goForward, createKey, // 創(chuàng)建location的key,用于唯一標(biāo)示該location,是隨機(jī)生成的 createPath, createHref, createLocation, // 創(chuàng)建location } }
createLocation方法:
function createLocation() { return { pathname, // url的基本路徑 search, // 查詢字段 hash, // url中的hash值 state, // url對(duì)應(yīng)的state字段 action, // 分為push、replace、pop三種 key // 生成方法為: Math.random().toString(36).substr(2, length) } }
三種方法各自執(zhí)行URL前進(jìn)的方式:
createBrowserHistory: pushState、replaceState
createHashHistory: location.hash=*** location.replace()
createMemoryHistory: 在內(nèi)存中進(jìn)行歷史記錄的存儲(chǔ)
偽代碼實(shí)現(xiàn):
// createBrowserHistory(HTML5)中的前進(jìn)實(shí)現(xiàn) function finishTransition(location) { ... const historyState = { key }; ... if (location.action === "PUSH") ) { window.history.pushState(historyState, null, path); } else { window.history.replaceState(historyState, null, path) } } // createHashHistory的內(nèi)部實(shí)現(xiàn) function finishTransition(location) { ... if (location.action === "PUSH") ) { window.location.hash = path; } else { window.location.replace( window.location.pathname + window.location.search + "#" + path ); } } // createMemoryHistory的內(nèi)部實(shí)現(xiàn) entries = []; function finishTransition(location) { ... switch (location.action) { case "PUSH": entries.push(location); break; case "REPLACE": entries[current] = location; break; } }
React-router的基本原理
URL對(duì)應(yīng)Location對(duì)象,而UI是由react的 components來決定的,這樣就轉(zhuǎn)變成location與components之間的同步問題。
什么是原型鏈每一個(gè)對(duì)象都會(huì)在內(nèi)部鏈接到另一個(gè)對(duì)象(該對(duì)象的原型對(duì)象),該對(duì)象有一個(gè)原型prototype,當(dāng)訪問對(duì)象的屬性或是方法的時(shí)候,不僅僅會(huì)在原對(duì)象上查找,還會(huì)順著原型鏈在原型對(duì)象的原型鏈上查找,直到查到null(所有原型鏈的頂層)為止。原型是JavaScript實(shí)現(xiàn)繼承的基礎(chǔ),new關(guān)鍵字做的主要的事情就是將實(shí)例對(duì)象的__proto__屬性指向原型對(duì)象的prototype。
什么是閉包閉包是javascript支持頭等函數(shù)的一種方式,它是一個(gè)能夠引用其內(nèi)部作用域變量(在本作用域第一次聲明的變量)的表達(dá)式,這個(gè)表達(dá)式可以賦值給某個(gè)變量,可以作為參數(shù)傳遞給函數(shù),也可以作為一個(gè)函數(shù)返回值返回。
閉包是函數(shù)開始執(zhí)行的時(shí)候被分配的一個(gè)棧幀,在函數(shù)執(zhí)行結(jié)束返回后仍不會(huì)被釋放(就好像一個(gè)棧幀被分配在堆里而不是棧里!)
閉包的應(yīng)用:
比如寫柯里化函數(shù)的時(shí)候利用閉包,保存參數(shù)在內(nèi)存中;
var currying = function(fun) { //格式化arguments var args = Array.prototype.slice.call(arguments, 1); return function() { //收集所有的參數(shù)在同一個(gè)數(shù)組中,進(jìn)行計(jì)算 var _args = args.concat(Array.prototype.slice.call(arguments)); return fun.apply(null, _args); }; }
?
模擬私有變量或是私有方法;
people = (num) => {
var num = num;
return {
increase: () => {
num++;
},
get: () => { return num; } }
}
man = people(4);
man.increase();
man.get();
避免引用錯(cuò)誤
(var i = 0; i < 4; i++) {
(function(_i) {
setTimeout(function() { console.log(_i)
}, 1000)
})(i)
}
?
圖片懶加載與預(yù)加載圖片懶加載的原理就是暫時(shí)不設(shè)置圖片的src屬性,而是將圖片的url隱藏起來,比如先寫在data-src里面,等某些事件觸發(fā)的時(shí)候(比如滾動(dòng)到底部,點(diǎn)擊加載圖片)再將圖片真實(shí)的url放進(jìn)src屬性里面,從而實(shí)現(xiàn)圖片的延遲加載
圖片預(yù)加載,是指在一些需要展示大量圖片的網(wǎng)站,實(shí)現(xiàn)圖片的提前加載。從而提升用戶體驗(yàn)。常用的方式有兩種,一種是隱藏在css的background的url屬性里面,一種是通過javascript的Image對(duì)象設(shè)置實(shí)例對(duì)象的src屬性實(shí)現(xiàn)圖片的預(yù)加載。相關(guān)代碼如下:
CSS預(yù)加載圖片方式:
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; } #preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; } #preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }
Javascript預(yù)加載圖片的方式:
function preloadImg(url) { var img = new Image(); img.src = url; if(img.complete) { //接下來可以使用圖片了 //do something here } else { img.onload = function() { //接下來可以使用圖片了 //do something here }; } }跨域
跨域的方式有很多種,最常用的是jsonp主要利用了script的開放策略:通過script標(biāo)簽引入一個(gè)js或者是一個(gè)其他后綴形式(如php,jsp等)的文件,此文件返回一個(gè)js函數(shù)的調(diào)用。缺點(diǎn)在于只支持get請(qǐng)求而且存在安全問題。
CORS跨域,關(guān)鍵在于服務(wù)器,如果服務(wù)器實(shí)現(xiàn)了CORS跨域的接口,那么就可以使用ajax(請(qǐng)求路徑為絕對(duì)路徑)進(jìn)行跨域請(qǐng)求。CORS請(qǐng)求分為兩種,一種是簡單請(qǐng)求,一種是非簡單請(qǐng)求。簡單請(qǐng)求是指請(qǐng)求方法在HEAD,GET,POST三者之間并且請(qǐng)求頭信息局限在
Accept
Accept-Language
Content-Language
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
非簡單請(qǐng)求請(qǐng)求頭:
(1)Access-Control-Request-Method
該字段是必須的,用來列出瀏覽器的CORS請(qǐng)求會(huì)用到哪些HTTP方法
(2)Access-Control-Request-Headers
該字段是一個(gè)逗號(hào)分隔的字符串,指定瀏覽器CORS請(qǐng)求會(huì)額外發(fā)送的頭信息字段
執(zhí)行簡單請(qǐng)求的時(shí)候,瀏覽器會(huì)在請(qǐng)求頭信息增加origin字段,服務(wù)器據(jù)此來判斷請(qǐng)求域名是否在許可范圍之內(nèi),來決定是否返回Access-Control-Allow-Origin字段。響應(yīng)頭有以下幾種:
(1)Access-Control-Allow-Origin
該字段是必須的。它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。
(2)Access-Control-Allow-Credentials
該字段可選。它的值是一個(gè)布爾值,表示是否允許發(fā)送Cookie。默認(rèn)情況下,Cookie不包括在CORS請(qǐng)求之中。設(shè)為true,即表示服務(wù)器明確許可,Cookie可以包含在請(qǐng)求中,一起發(fā)給服務(wù)器。這個(gè)值也只能設(shè)為true,如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可。
(3)Access-Control-Expose-Headers
該字段可選。CORS請(qǐng)求時(shí),XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。
(4)Access-Control-Max-Age
Access-Control-Max-Age 首部字段指明了預(yù)檢請(qǐng)求的響應(yīng)的有效時(shí)間。
(5)Access-Control-Allow-Methods
Access-Control-Allow-Methods 首部字段用于預(yù)檢請(qǐng)求的響應(yīng)。其指明了實(shí)際請(qǐng)求所允許使用的 HTTP 方法。
(6)Access-Control-Allow-Headers
Access-Control-Allow-Headers首部字段用于預(yù)檢請(qǐng)求的響應(yīng)。其指明了實(shí)際請(qǐng)求中允許攜帶的首部字段。
其他方法:document.domin,html5的postMessage,window.name等
函數(shù)節(jié)流和函數(shù)防抖函數(shù)節(jié)流讓指函數(shù)有規(guī)律的進(jìn)行調(diào)用,應(yīng)用場景:window.resize,游戲中子彈發(fā)射(1s只能發(fā)射一顆子彈)等;
函數(shù)防抖讓函數(shù)在"調(diào)用""之后的一段時(shí)間后生效,應(yīng)用場景:輸入框(例:在用戶停止輸入的500ms后再處理用戶數(shù)據(jù))。
//函數(shù)節(jié)流 /* * @params {Function} fun 調(diào)用函數(shù) * @params {delay} number 延遲時(shí)間 */ const throttle = (fun, delay, ...rest) => { let last = null; return () => { const now = + new Date(); if (now - last > delay) { fun(rest); last = now; } } } //實(shí)例 const throttleExample = throttle(() => console.log(1), 1000); //調(diào)用 throttleExample(); throttleExample(); throttleExample(); //函數(shù)防抖 const debouce = (fun, delay, ...rest) => { let timer = null; return () => { clearTimeout(timer); timer = setTimeout(() => { fun(rest); }, delay); } } //實(shí)例 const debouceExample = debouce(() => console.log(1), 1000); //調(diào)用 debouceExample(); debouceExample(); debouceExample();快速排序
從數(shù)列中挑出一個(gè)元素,稱為"基準(zhǔn)"(pivot),
重新排序數(shù)列,所有比基準(zhǔn)值小的元素?cái)[放在基準(zhǔn)前面,所有比基準(zhǔn)值大的元素?cái)[在基準(zhǔn)后面(相同的數(shù)可以到任一邊)。在這個(gè)分區(qū)結(jié)束之后,該基準(zhǔn)就處于數(shù)列的中間位置。這個(gè)稱為分區(qū)(partition)操作。
遞歸地(recursively)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序。
時(shí)間復(fù)雜度平均情況:O(nlog n) 最快:O(n^{2}) 空間復(fù)雜度: O(log n)
var quickSort = function(arr) { console.time("2.快速排序耗時(shí)"); if (arr.length <= 1) { return arr; } var pivot = arr.splice(0, 1)[0]; var left = []; var right = []; for (var i = 0; i < arr.length; i++){ if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } console.timeEnd("2.快速排序耗時(shí)"); return quickSort(left).concat([pivot], quickSort(right)); }; var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(quickSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]AMD和CMD的區(qū)別
AMD 是 RequireJS 在推廣過程中對(duì)模塊定義的規(guī)范化產(chǎn)出。
CMD 是 SeaJS 在推廣過程中對(duì)模塊定義的規(guī)范化產(chǎn)出。
對(duì)于依賴的模塊,AMD 是提前執(zhí)行,CMD 是延遲執(zhí)行。不過 RequireJS 從 2.0 開始,也改成可以延遲執(zhí)行(根據(jù)寫法不同,處理方式不同)。CMD 推崇 as lazy as possible.
CMD 推崇依賴就近,AMD 推崇依賴前置。
AMD 的 API 默認(rèn)是一個(gè)當(dāng)多個(gè)用,CMD 的 API 嚴(yán)格區(qū)分,推崇職責(zé)單一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,沒有全局 require,而是根據(jù)模塊系統(tǒng)的完備性,提供 seajs.use 來實(shí)現(xiàn)模塊系統(tǒng)的加載啟動(dòng)。CMD 里,每個(gè) API 都簡單純粹。
JavaScript內(nèi)存泄露的原因以及如何去手動(dòng)釋放內(nèi)存易出現(xiàn)泄露的場景
XMLHttpRequest 泄漏發(fā)生在IE7-8,釋放方法,將XMLHttpRequest實(shí)例對(duì)象設(shè)置為Null;
DOM&BOM等COM對(duì)象循環(huán)綁定 泄漏發(fā)生在IE6-8,釋放方法,切斷循環(huán)引用,將對(duì)對(duì)象的應(yīng)用設(shè)置為Null;
定時(shí)器(嚴(yán)格上說不能算是泄露,是被閉包持有了,是正常的表現(xiàn)),對(duì)于閉包中無用的變量可以使用delete操作符進(jìn)行釋放;
JavaScript垃圾回收機(jī)制
引用計(jì)數(shù)
此算法把“對(duì)象是否不再需要”簡化定義為“對(duì)象有沒有其他對(duì)象引用到它”。如果沒有引用指向該對(duì)象(零引用),對(duì)象將被垃圾回收機(jī)制回收。
限制:無法處理循環(huán)引用。在下面的例子中,兩個(gè)對(duì)象被創(chuàng)建,并互相引用,形成了一個(gè)循環(huán)。它們被調(diào)用之后不會(huì)離開函數(shù)作用域,所以它們已經(jīng)沒有用了,可以被回收了。然而,引用計(jì)數(shù)算法考慮到它們互相都有至少一次引用,所以它們不會(huì)被回收。
標(biāo)記清除
當(dāng)變量進(jìn)入環(huán)境時(shí),例如,在函數(shù)中聲明一個(gè)變量,就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”。從邏輯上講,永遠(yuǎn)不能釋放進(jìn)入環(huán)境的變量所占用的內(nèi)存,因?yàn)橹灰獔?zhí)行流進(jìn)入相應(yīng)的環(huán)境,就可能會(huì)用到它們。而當(dāng)變量離開環(huán)境時(shí),則將其標(biāo)記為“離開環(huán)境”。
垃圾回收器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記(當(dāng)然,可以使用任何標(biāo)記方式)。然后,它會(huì)去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記(閉包)。而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。最后,垃圾回收器完成內(nèi)存清除工作,銷毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間。
柯里化函數(shù)所謂的柯里化函數(shù)簡單的說就是將本來接受多個(gè)參數(shù)的函數(shù)變?yōu)橹唤邮芤粋€(gè)參數(shù)的函數(shù)。柯里化函數(shù)的模板和實(shí)例如下:
var currying = function(fun) { //格式化arguments var args = Array.prototype.slice.call(arguments, 1); return function() { //收集所有的參數(shù)在同一個(gè)數(shù)組中,進(jìn)行計(jì)算 var _args = args.concat(Array.prototype.slice.call(arguments)); return fun.apply(null, _args); }; } var add = currying(function() { var args = Array.prototype.slice.call(arguments); return args.reduce(function(a, b) { return a + b; }); }) add(1, 2, 4) /* * 經(jīng)典面試題 * 函數(shù)參數(shù)不定回調(diào)函數(shù)數(shù)目不定 * 編寫函數(shù)實(shí)現(xiàn): * add(1,2,3,4,5)==15 * add(1,2)(3,4)(5)==15 */ function add() { // 第一次執(zhí)行時(shí),定義一個(gè)數(shù)組專門用來存儲(chǔ)所有的參數(shù) var _args = [].slice.call(arguments); // 在內(nèi)部聲明一個(gè)函數(shù),利用閉包的特性保存_args并收集所有的參數(shù)值 var adder = function () { var _adder = function() { [].push.apply(_args, [].slice.call(arguments)); return _adder; }; // 利用隱式轉(zhuǎn)換的特性,當(dāng)最后執(zhí)行時(shí)隱式轉(zhuǎn)換,并計(jì)算最終的值返回 _adder.toString = function () { return _args.reduce(function (a, b) { return a + b; }); } return _adder; } return adder.apply(null, _args); } // 輸出結(jié)果,可自由組合的參數(shù) console.log(add(1, 2, 3, 4, 5)); // 15 console.log(add(1, 2, 3, 4)(5)); // 15 console.log(add(1)(2)(3)(4)(5)); // 15Less常用特性
變量(@color = #fff)
混合(Mixin)
內(nèi)置函數(shù)(顏色,字符串,類型判斷,數(shù)學(xué))
循環(huán)
嵌套
運(yùn)算
導(dǎo)入(@import)
ES6常用特性變量定義(let和const,可變與不可變,const定義對(duì)象的特殊情況)
解構(gòu)賦值
模板字符串
數(shù)組新API(例:Array.from(),entries(),values(),keys())
箭頭函數(shù)(rest參數(shù),擴(kuò)展運(yùn)算符,::綁定this)
Set和Map數(shù)據(jù)結(jié)構(gòu)(set實(shí)例成員值唯一存儲(chǔ)key值,map實(shí)例存儲(chǔ)鍵值對(duì)(key-value))
Promise對(duì)象(前端異步解決方案進(jìn)化史,generator函數(shù),async函數(shù))
Class語法糖(super關(guān)鍵字)
react中setState的原理題目:
import React from "react" class App extends React.Component { constructor() { super(); this.state = { value: 0 } } componentDidMount() { this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); setTimeout(() => { this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); }, 0) } }
答案: 0、0、0、2、3;
分析:
當(dāng)setState方法調(diào)用的時(shí)候React就會(huì)重新調(diào)用render方法來重新渲染組件;setState通過一個(gè)隊(duì)列來更新state,當(dāng)調(diào)用setState方法的時(shí)候會(huì)將需要更新的state放入這個(gè)狀態(tài)隊(duì)列中,這個(gè)隊(duì)列會(huì)高效的批量更新state;
源碼地址:enqueueUpdate
function enqueueUpdate(component) { ensureInjected(); //判斷是否處于批量更新模式 if (!batchingStrategy.isBatchingUpdates) { //關(guān)鍵!下面的代碼片段是這個(gè)方法的源碼 batchingStrategy.batchedUpdates(enqueueUpdate, component); return; } //如果處于批量更新模式,則將這個(gè)組件保存在dirtyComponents dirtyComponents.push(component); }
源碼地址:ReactDefaultBatchingStrategy
//batchingStrategy對(duì)象 var ReactDefaultBatchingStrategy = { //注意默認(rèn)為false isBatchingUpdates: false, batchedUpdates: function(callback, a, b, c, d, e) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; ReactDefaultBatchingStrategy.isBatchingUpdates = true; if (alreadyBatchingUpdates) { callback(a, b, c, d, e); } else { //關(guān)鍵!!!事務(wù)的理解 transaction.perform(callback, null, a, b, c, d, e); } }, };
源碼地址:Transaction
如圖:事務(wù)會(huì)將所需要執(zhí)行的方法(圖中的anyMethod)使用wrapper封裝起來,再通過perform方法執(zhí)行該方法,但在perform執(zhí)行之前會(huì)先執(zhí)行所有wrapper中的initialize方法,perform方法執(zhí)行結(jié)束后,再執(zhí)行所有的close方法;
var Transaction = require("./Transaction"); // 我們自己定義的 var MyTransaction = function() { //do something }; Object.assign(MyTransaction.prototype, Transaction.Mixin, { //需要自定義一個(gè)getTransactionWrappers對(duì)象,獲取所有需要封裝的initialize方法和close方法 getTransactionWrappers: function() { return [{ initialize: function() { console.log("before method perform"); }, close: function() { console.log("after method perform"); } }]; }; }); //實(shí)例化一個(gè)transaction var transaction = new MyTransaction(); //需要調(diào)用的方法 var testMethod = function() { console.log("test"); } transaction.perform(testMethod); //before method perform //test //after method perform
理解題目的關(guān)鍵是,整個(gè)組件渲染到DOM中的過程就已經(jīng)處于一次大的事務(wù)中了,因此在componentDidMount方法中調(diào)用setState的時(shí)候 ReactDefaultBatchingStrategy.isBatchingUpdates = true;這句代碼已經(jīng)執(zhí)行過了,所以setState的結(jié)果并沒有立即生效,而是扔進(jìn)了dirtyComponent;因此執(zhí)行三次setState的結(jié)果this.state.value的值依然是0,而setTimeout中的兩次setState由于沒有調(diào)用過batchedUpdates方法(isBatchingUpdates默認(rèn)為false),所以setState方法立即生效,第二次setSState同理
XSS與CSRF介紹XSS是一種跨站腳本攻擊,是屬于代碼注入的一種,攻擊者通過將代碼注入網(wǎng)頁中,其他用戶看到會(huì)受到影響(代碼內(nèi)容有請(qǐng)求外部服務(wù)器);
CSRF是一種跨站請(qǐng)求偽造,冒充用戶發(fā)起請(qǐng)求,完成一些違背用戶請(qǐng)求的行為(刪帖,改密碼,發(fā)郵件,發(fā)帖等)
防御方法舉例:
對(duì)一些關(guān)鍵字和特殊字符進(jìn)行過濾(<>,?,script等),或?qū)τ脩糨斎雰?nèi)容進(jìn)行URL編碼(encodeURIComponent);
Cookie不要存放用戶名和密碼,對(duì)cookie信息進(jìn)行MD5等算法散列存放,必要時(shí)可以將IP和cookie綁定;
后記時(shí)隔三個(gè)月,終于迎來了博文的更新,有看到博友在評(píng)論留言:
心里很溫暖,這篇不算博文的博文就當(dāng)是回歸之作吧,接下來的時(shí)間會(huì)盡量保持在一周一更,實(shí)習(xí)結(jié)束有的是時(shí)間了,哈哈哈。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/83052.html
摘要:推薦高性能網(wǎng)站建設(shè)指南高性能網(wǎng)站建設(shè)進(jìn)階指南理由在讀完前幾本書之后我們對(duì)前端的性能和自己的代碼的效率已經(jīng)達(dá)到相當(dāng)?shù)母叨攘耍缓笪覀冊(cè)诮佑|一些前端工程師的一些精髓。 WEB前端研發(fā)工程師,在國內(nèi)算是一個(gè)朝陽職業(yè),這個(gè)領(lǐng)域沒有學(xué)校的正規(guī)教育,大多數(shù)人都是靠自己自學(xué)成才。本文主要介紹自己從事web開發(fā)以來(從大二至今)看過的書籍和自己的成長過程,目的是給想了解JavaScript或者是剛...
摘要:推薦高性能網(wǎng)站建設(shè)指南高性能網(wǎng)站建設(shè)進(jìn)階指南理由在讀完前幾本書之后我們對(duì)前端的性能和自己的代碼的效率已經(jīng)達(dá)到相當(dāng)?shù)母叨攘耍缓笪覀冊(cè)诮佑|一些前端工程師的一些精髓。 WEB前端研發(fā)工程師,在國內(nèi)算是一個(gè)朝陽職業(yè),這個(gè)領(lǐng)域沒有學(xué)校的正規(guī)教育,大多數(shù)人都是靠自己自學(xué)成才。本文主要介紹自己從事web開發(fā)以來(從大二至今)看過的書籍和自己的成長過程,目的是給想了解JavaScript或者是剛...
摘要:推薦高性能網(wǎng)站建設(shè)指南高性能網(wǎng)站建設(shè)進(jìn)階指南理由在讀完前幾本書之后我們對(duì)前端的性能和自己的代碼的效率已經(jīng)達(dá)到相當(dāng)?shù)母叨攘耍缓笪覀冊(cè)诮佑|一些前端工程師的一些精髓。 WEB前端研發(fā)工程師,在國內(nèi)算是一個(gè)朝陽職業(yè),這個(gè)領(lǐng)域沒有學(xué)校的正規(guī)教育,大多數(shù)人都是靠自己自學(xué)成才。本文主要介紹自己從事web開發(fā)以來(從大二至今)看過的書籍和自己的成長過程,目的是給想了解JavaScript或者是剛...
摘要:業(yè)務(wù)和架構(gòu)不分家,架構(gòu)是建立在對(duì)業(yè)務(wù)的理解之上的。主鍵最好保持順序遞增,隨機(jī)主鍵會(huì)導(dǎo)致聚簇索引樹頻繁分裂,隨機(jī)增多,數(shù)據(jù)離散,性能下降。沒有索引的更新,可能會(huì)導(dǎo)致全表數(shù)據(jù)都被鎖住。 本博客并非全部原創(chuàng),其實(shí)是一個(gè)知識(shí)的歸納和匯總,里面我引用了很多網(wǎng)上、書上的內(nèi)容。也給出了相關(guān)的鏈接。 本文涉及的知識(shí)點(diǎn)比較多,大家可以根據(jù)關(guān)鍵字去搜索相關(guān)的內(nèi)容和購買相應(yīng)的書籍進(jìn)行系統(tǒng)的學(xué)習(xí)。不對(duì)的地方...
摘要:去年年底因?yàn)槭褂昧嗽拼鎯?chǔ)和其他方面的原因,計(jì)劃的將服務(wù)器縮減一個(gè)機(jī)柜出來。云服務(wù)的回源服務(wù)器的配置中間漏了一臺(tái),后期給補(bǔ)上了。監(jiān)控遷移完畢之后,除了常規(guī)的業(yè)務(wù)代碼,還需要注意圖片資源的回源是否正常服務(wù)器壓力是否正常檢查日志是否出現(xiàn)錯(cuò)誤。 去年年底因?yàn)槭褂昧嗽拼鎯?chǔ)和其他方面的原因,計(jì)劃的將服務(wù)器縮減一個(gè)機(jī)柜出來。這樣今年每月機(jī)房的費(fèi)用可以減少1萬左右。前前后后抽空在弄這個(gè)任務(wù),現(xiàn)做個(gè)筆記...
閱讀 4607·2021-09-26 09:55
閱讀 1352·2019-12-27 12:16
閱讀 879·2019-08-30 15:56
閱讀 1895·2019-08-30 14:05
閱讀 983·2019-08-30 13:05
閱讀 1261·2019-08-30 10:59
閱讀 1437·2019-08-26 16:19
閱讀 1880·2019-08-26 13:47