落魄前端,整理给自己的前端知识体系复习大纲(上篇,2w字)
作者:逐步前行
https://juejin.im/post/6867715946941775885
閱讀前言
轉(zhuǎn)眼間9月的到來,十分感慨這時(shí)光的飛逝。9月對程序員有著十分重要的意義,想在這個(gè)優(yōu)勝劣汰的代碼世界活下去,金3銀4,金9銀10,都屬于選擇的機(jī)會(huì)。
在這優(yōu)勢略汰且經(jīng)濟(jì)回隴的狀態(tài)下,筆者身處央企都無法安穩(wěn),如今也要考慮工作的問題(有廣州?內(nèi)推?,歡迎聯(lián)系),我們可以選擇的只能是,逐步的打好自己的基礎(chǔ),才能在不安穩(wěn)的社會(huì)形態(tài)下,逆行保持自己的安穩(wěn)。筆者也該復(fù)習(xí)復(fù)習(xí),在此匯總一下自己過去所學(xué)過的基礎(chǔ)。
本文的難度級別,個(gè)人定位為中級前端開發(fā)工程師。且自負(fù)的認(rèn)為前端重要基礎(chǔ)的均匯總,如有遺漏,希望你評論噴我,噴我如果能學(xué)習(xí)到知識,愿聽聞。筆者也是逐步前進(jìn)的小伙,當(dāng)前也需要及時(shí)的補(bǔ)充自己,過程如有不對的地方,盡快指出。如文章對你有幫助,希望能給于鼓勵(lì),手動(dòng)點(diǎn)個(gè)贊吧。
匯總內(nèi)容包含看過的書籍,自己對程序的理解,以及部分大神的借鑒(很多都是曾經(jīng)記下的知識點(diǎn),來源我也忘記是從哪里,如沒有提及希望包涵)。
但文章全文,均為筆者一字一字手敲。寫給自己供于復(fù)習(xí),同時(shí)分享給在前端一起努力朋友。
一.前端基礎(chǔ)
前端基礎(chǔ),個(gè)人認(rèn)為就是html + js + css。無論過程如何,無論你用的是less還是sass,無論你用的vue還是react,輸出的結(jié)果,只有html + js + css。
此部分列舉,筆者覺得重點(diǎn)的知識點(diǎn),如有遺漏,歡迎指出。
1)html篇
html章節(jié),本文僅列出筆者任務(wù)相對重要的知識點(diǎn),且介紹上,針對重點(diǎn)。當(dāng)然,遺漏很正常,希望能收到你的意見。
1.語義化
所謂,語義化的標(biāo)簽,說明讓標(biāo)簽有自己的含義。也是近十年。最典型的栗子就是header,footer等,它可以讓你在沒有樣式的情況下,就大概能想到,他就是個(gè)頭部或者底部。他存在的意義,就是讓前端開發(fā)人員,在開發(fā)過程中,更容易去閱讀代碼,以及明白這些代碼的意義。
它的好處是:1.能夠更好的展示內(nèi)容結(jié)構(gòu)2.便于團(tuán)隊(duì)的維護(hù)與開發(fā)3.有利于SEO,爬蟲可以分析每個(gè)關(guān)鍵詞的權(quán)重。4.方便其他設(shè)備解析 (如屏幕閱讀器)
2.SEO
作為前端,你不得不知道的SEO,這涉及到公司的網(wǎng)站推廣。
SEO,中文稱搜索引擎優(yōu)化,一種利用搜索引擎的搜索規(guī)則來提高目前網(wǎng)站在有關(guān)搜索引擎內(nèi)的自然排名的方式。他的實(shí)現(xiàn)原來分別為,頁面抓取,分析入庫,檢索排序。
有興趣深入SEO優(yōu)化的朋友:segmentfault.com/a/119000001…
3.doctype
前端經(jīng)常在html頭部看到DOCTYPE的聲明,一般常位于文檔的第一行。那么他的作用是什么,可能對新的瀏覽器或者新的網(wǎng)站暫無什么影響,但是相對古老的瀏覽器或者是網(wǎng)站,可能會(huì)出現(xiàn)不同。因?yàn)闉g覽器有標(biāo)準(zhǔn)模式與兼容模式,差異相對比較大。
標(biāo)準(zhǔn)模式的渲染方式和 JS 引擎的解析方式都是以該瀏覽器支持的最高標(biāo)準(zhǔn)運(yùn)行。兼容模式中,頁面以寬松的向后兼容的方式顯示 ,模擬老式瀏覽器的行為以防止站點(diǎn)無法工作。
而DOCTYPE的存在,就是為了聲明,該頁面使用標(biāo)準(zhǔn)模式。不聲明,可能一些舊的網(wǎng)站會(huì)出現(xiàn)兼容模式。
4.link與@import
link與import , 本質(zhì)使用上,我們都是用他來引入css,但是他們有一定的區(qū)別。
link是一種引入資源的標(biāo)簽,import是引入css的方式。所以,import引入的只能是css,而link可以引入所有的資源,包括圖片,RSS等。
加載順序上也有一些差異。link引用的CSS會(huì)同時(shí)被加載。import引用的CSS會(huì)等到頁面全部被下載完再加載。
兼容性的差別。link無任何兼容問題,import兼容IE5以上。(當(dāng)然,IE5估計(jì)也找不到了)
動(dòng)態(tài)引入樣式link可以后期引入樣式,而import是不可以后期引入的,只能初始化頁面之前引入。
復(fù)用率的問題import可以復(fù)用之前的css文件,而link只能一次引用一個(gè)文件。當(dāng)然,import復(fù)用文件時(shí),在瀏覽器實(shí)際上是加載了多個(gè)文件,會(huì)有多個(gè)請求。而每一個(gè)link只是一個(gè)http請求。
5.async與defer
首先這兩個(gè)東西為什么而存在的問題。在日漸復(fù)雜的前端,異常已經(jīng)是程序的一部分。如果出現(xiàn)一些小問題,或者服務(wù)器加載上出現(xiàn)延遲。而我們默認(rèn)的引入的script腳本,會(huì)阻塞后續(xù)的DOM渲染。一旦沒有部分異常無法及時(shí)加載完成,那么我們的頁面因?yàn)樽枞麊栴},將整個(gè)白屏。
也許我們可以保證自己服務(wù)器的正常,但是你決定保證不了第三方服務(wù)器的正常,于是引入了async和defer來優(yōu)化這個(gè)問題。
再來談?wù)剆cript的默認(rèn),async,defer的之前的差異。
默認(rèn)情況下:瀏覽器會(huì)立即加載并執(zhí)行指定的腳本。指定的腳本,指在script標(biāo)簽之上的腳本。所以,如果script放在header中,而對應(yīng)的文件還未加載完成,會(huì)形成阻塞。所以這就是現(xiàn)在很多頁面,都會(huì)使用默認(rèn)且把scipt放在頁面結(jié)尾的原因。
async情況下:async ,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進(jìn)行(異步)。async是亂序的。
defer情況下:defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進(jìn)行(異步),但是 script.js 的執(zhí)行要在所有元素解析完成之后,DOMContentLoaded 事件觸發(fā)之前完成。defer是順序執(zhí)行。
此外,async跟defer,不支持或者不兼容IE9一下瀏覽器,總體來說,筆者還是覺得script放最下方靠譜一些。
6.文本元素的冒泡與委托
適合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
優(yōu)點(diǎn):1.減少事件注冊,節(jié)省內(nèi)存。例如上面代碼,只指定 父元素的處理程序,即可管理所有所有子元素的“click”事件;2.簡化了dom節(jié)點(diǎn)更新時(shí),相應(yīng)事件的更新
缺點(diǎn):1.利用事件冒泡的原理,不支持不冒泡的事件;2.層級過多,冒泡過程中,可能會(huì)被某層阻止掉;3. 理論上委托會(huì)導(dǎo)致瀏覽器頻繁調(diào)用處理函數(shù),雖然很可能不需要處理。所以建議就近委托,比如在ol上代理li,而不是在document上代理li。4. 把所有事件都用代理就可能會(huì)出現(xiàn)事件誤判。比如,在document中代理了所有button的click事件,另外的人在引用改js時(shí),可能不知道,造成單擊button觸發(fā)了兩個(gè)click事件。
2)css篇
css章節(jié),本文僅列出筆者任務(wù)相對重要的知識點(diǎn),且介紹上,針對重點(diǎn)。當(dāng)然,遺漏很正常,希望能收到你的意見。
1.盒子模型
盒子模型,個(gè)人的理解,就是一個(gè)來裝html標(biāo)簽的容器,包裝的內(nèi)容包括content+padding+border+margin。由這四個(gè)組成我們的"盒子"。
我們?nèi)粘?赡軙?huì)遇到不同的瀏覽器,元素的高寬不一致。除了可能是瀏覽器內(nèi)置的margin跟padding不同之外,也可能是IE跟w3c的盒子模型組成不同。
以下是兩種不同盒子的分類:
W3C盒子模型:可通過box-sizing: content-box來設(shè)置,他包含content+padding+border+margin。
IE盒子模型:可通過box-sizing: border-box來設(shè)置,content+margin。其中content包含border,padding。
2.BFC
簡單的個(gè)人理解,block formatting context,塊級格式化上下文。產(chǎn)生了BFC的,形成了獨(dú)立容器,他的特性就是不會(huì)再布局中影響到外邊的元素。
他的特性:
1)BFC邊距會(huì)重疊。
2)BFC的內(nèi)外元素互相不影響
3)BFC不會(huì)與浮動(dòng)元素發(fā)生重疊
4)BFC元素的高度計(jì)算會(huì)包括元素內(nèi)的浮動(dòng)元素的高度
觸發(fā)的條件是:
1)body 根元素
2)浮動(dòng)元素:float 除 none 以外的值
3)絕對定位元素:position (absolute、fixed)
4)display 為 inline-block、table-cells、flex,table-caption
5)overflow 除了 visible 以外的值 (hidden、auto、scroll)
此外,除了BFC,還有IFC、GFC、FFC的概念。我們簡單了解一下。
GFC:可簡單理解為grid布局
FFC:可簡單理解為flex布局。
IFC:內(nèi)聯(lián)格式化上下文,簡單理解為:inline-block。
水平方向上的 margin,border 和 padding在框之間得到保留。框在垂直方向上可以以不同的方式對齊:它們的頂部或底部對齊,或根據(jù)其中文字的基線對齊。包含那些框的長方形區(qū)域,會(huì)形成一行,叫做行框。inline-block的元素的內(nèi)部是一個(gè)BFC,但是它本身可以和其它inline元素一起形成IFC。
3.flex布局
flex,即彈性布局。一個(gè)由css3引入,為我們的盒子屬性帶來靈活性的一種布局方式。一旦父級采用了flex布局,里邊的子控件將收flex布局限制,部分原本的樣式(如float:left)也會(huì)失效。
基本api不做講解,不熟悉可以看看:www.ruanyifeng.com/blog/2015/0…
特別注意:flex:0 0 30%的意義:等于flex-grow=0(默認(rèn)不放大)+flex-shrink=0(不縮小)+flex-basis=30%( 項(xiàng)目占據(jù)主軸的空間)
4.css3新特性
背景,支持RGBA透明度,一次多背景圖
支持媒體查詢
支持陰影,漸變,陰影
支持邊框圖片,border-image: url(border.png) 30 30 round
支持transform位移系列
支持過渡效果transition
支持自定義字體
引入flex/grid布局
引入多種選擇器
其他不做詳細(xì)說明,有興趣搜一下css3新特性
5.圖片格式
前端的圖片分類格式,其實(shí)是性能優(yōu)化的很大部分。選擇好圖片的類型,對前端的性能影響非常大。
而前端對圖片的精髓,一方面是對圖片大小的評估,一方面是對圖片的類型選擇。
他的大小可以這樣判斷:
比如一張200*200的圖片大小,這時(shí)候,他的像素點(diǎn)有40000個(gè)。每個(gè)像素有 4 個(gè)通道, 所以一共有160000個(gè)字節(jié),所以,我們評估該圖片的大小大概為:160000/1024 ?約等于 156(KB), 如果大很多,說明圖片大小有優(yōu)化控件。如果小很多,說明此時(shí)是模糊的。
| png | 適合顏色簡單,但是對圖片質(zhì)量比較高。日常用的png8,此外還有png32, | 適合logo體積太大一般不用 |
| jpeg | 不影響圖片質(zhì)量的情況有損壓縮,banner圖。適合大圖。 | 壓縮后大小可省略很多,一般大圖使用 |
| svg | 對性能有損耗,體積小,壓縮性搶。可在質(zhì)量不下降的過程被放大 | 部分瀏覽器兼容性不太好 |
| webp | 只針對谷歌,兼容性不好。圖片大小能壓縮30~40%。 | 谷歌瀏覽器用,如有非常注重性能的產(chǎn)品,可判斷瀏覽器加載不同類型圖片 |
| base64 | 壓縮成字符流,實(shí)際大小是變大了,但是好處就是減少了http請求 | 一般也針對小圖標(biāo) |
6.移動(dòng)端適配
列舉一下筆者所知道的適配方式:
1)媒體查詢。該方案的話,個(gè)人覺得是最佳的方案,也是常用UI庫非常喜歡的用處理方式之一。唯一不好的是:多套媒體方案,也意味多份的工作量。
2)vw/vh利用單位vw/vh進(jìn)行布局。該方案的話,對整體的布局還是相對穩(wěn)定,但是對部分細(xì)節(jié)等處理還是不優(yōu)化。且遇到手機(jī)屏幕差異較大的話,會(huì)出現(xiàn)嚴(yán)重的視差。
3)rem相對穩(wěn)定的方法。根據(jù)屏幕大小計(jì)算出font-size;但是只能求良好,很難求精。如果UI對一像素非常的敏感,這個(gè)方案可能是個(gè)非常糟糕的選擇。
4)類似小程序rpx。相信原生小程序開發(fā)者都用過rpx。這里其實(shí)原理有點(diǎn)類似rem。但是,卻不是按屏幕大小去計(jì)算,而是不同的屏幕定義了自己的標(biāo)準(zhǔn)。
7.常見兼容性
這個(gè)問題本次只列舉了幾個(gè)常見的,非全部列出。如需具體,可另查資料。
1)間距差異是否大,導(dǎo)致文本換行,或者間隔太大。原因:每個(gè)瀏覽器的margin和padding的默認(rèn)值不同。解決方案:全局文件設(shè)置統(tǒng)一默認(rèn)margin和padding。
2)圖片默認(rèn)有間距原因:因?yàn)閕mg標(biāo)簽是行內(nèi)屬性標(biāo)簽,所以只要不超出容器寬度,img標(biāo)簽都會(huì)排在一行里,但是部分瀏覽器的img標(biāo)簽之間會(huì)有個(gè)間距。去掉這個(gè)間距使用float是正道。(我的一個(gè)學(xué)生使用負(fù)margin,雖然能解決,但負(fù)margin本身就是容易引起瀏覽器兼容問題的用法,所以我禁止他們使用)解決方案:使用float屬性為img布局
3)較小的高度(小于10px),時(shí),ie可能會(huì)超出高度原因:IE有一個(gè)默認(rèn)的行高的高度解決方案:給超出高度的標(biāo)簽設(shè)置overflow:hidden;或者設(shè)置行高line-height 小于你設(shè)置的高度。
為min-height本身就是一個(gè)不兼容的CSS屬性
4)透明度兼容設(shè)置原因:不同瀏覽器各自透明度關(guān)鍵字不統(tǒng)一。解決方案:filter:alpha(opacity=50); -moz-opacity:0.5; ?-khtml-opacity: 0.5; opacity: 0.5;
5)IE的hover圖片會(huì)閃爍原因:IE6的每次觸發(fā) hover 的時(shí)候都會(huì)重新加載解決方案:提前緩存文件。document.execCommand("BackgroundImageCache", false, true);
8.垂直居中
該回復(fù)只給與思路,沒有具體寫法。因?yàn)槲矣X得大家都應(yīng)該懂。
已知寬高:1.margin 自己算高寬 2.定位 + margin-top + margin-left3.定位 + margin:auto
未知寬高:1.transform 但有IE兼容的問題2.flex 布局3.display: table-cell
9.實(shí)現(xiàn)1px
首先你可能需要了解一下物理像素跟獨(dú)立像素的區(qū)別。
物理像素:一個(gè)物理像素是顯示器(手機(jī)屏幕)上最小的物理顯示單元,如:iPhone6上就有7501334個(gè)物理像素顆粒。獨(dú)立像素:邏輯像素,程序使用的虛擬像素。如:iPhone6上就有375677個(gè)獨(dú)立像素。
那么如何實(shí)現(xiàn)1px呢:1.利用 transfrom 的 scale 縮放來實(shí)現(xiàn)2.利用 background 的 line-gradient 線性漸變來實(shí)現(xiàn)3.meta viewport修改成1比0.5。這樣整個(gè)屏幕的大小縮小了0.5。4.利用box-shadow
10.三列布局
該回復(fù)只給思路
1.CSS浮動(dòng)第一個(gè)float:left,第二個(gè)float:right,第三個(gè)設(shè)置margin-left和margin-right
2.絕對定位法第一個(gè)定位到left,第二個(gè)定位到right,第三個(gè)設(shè)置margin-left和margin-right
3.flex布局
11.樣式優(yōu)化
初步聊聊個(gè)人的樣式優(yōu)化方案如下:
1.避免css層級太深。有興趣了解一下css tree如何跟html tree融合成dom tree。2.首屏(特別是緩沖效果圖)可適當(dāng)使用內(nèi)聯(lián)元素。這樣有利于更快的顯示。3.異步加載CSS。非首次重要引入的css文件,不放在head里邊。這樣會(huì)引起阻塞。4.減少 回流 的屬性。如display:none可以考慮使用visibility5.適當(dāng)使用GPU渲染。如tranfrom等。6.css動(dòng)畫的性能,是遠(yuǎn)遠(yuǎn)的大于js動(dòng)畫性能。7.利用工具壓縮,去重。
12.偽類和偽元素
偽類和偽元素的根本區(qū)別在于:它們是否創(chuàng)造了新的元素
偽類,指可以通過元素選擇器,就可以實(shí)現(xiàn)的效果,如frist-child,active等。而偽元素,是指需要通過創(chuàng)元素,才可以實(shí)現(xiàn)的效果,如first-letter,before,after等。
具體元素跟寫法有興趣,可參考:blog.csdn.net/qq_27674439…
3)javaScript篇
javaScript篇,由于擴(kuò)展性十分全。對于大神來說,每一個(gè)點(diǎn),都可以做一篇簡介參考。本文只能是概念上的簡介,或者是個(gè)人對應(yīng)的理解。如理解有誤,歡迎吐槽。
1.內(nèi)置對象
內(nèi)置對象,也叫原始類型。
原始類型有5個(gè),null,undefined,boolean,number,string。es6引入了symbol,可以用來做獨(dú)立標(biāo)識用。es10引入了bigint, 主要用的大數(shù)據(jù)。number最大值2的53次方,超過只能使用bigint。截至目前為止,一共是7個(gè)。
原始類型存儲(chǔ)的都是值,他的原型匯總,是沒有任何函數(shù)的。如果你看到類型有函數(shù),比如toString,那說明類型給轉(zhuǎn)換為了對象類型,此時(shí)才有toString方法。
原始類型存儲(chǔ)的是值,對象類型存儲(chǔ)的是地址。
2.閉包
簡單的理解是,一個(gè)綁定了執(zhí)行環(huán)境的函數(shù),可以訪問到外部環(huán)境的變量。
他的好處就是:變量常駐內(nèi)存,對于實(shí)現(xiàn)某些業(yè)務(wù)很有幫助,比如計(jì)數(shù)器之類的。架起了一座橋梁,讓函數(shù)外部訪問函數(shù)內(nèi)部變量成為可能。私有化,一定程序上解決命名沖突問題,可以實(shí)現(xiàn)私有變量。
缺陷是:他的變量常駐在內(nèi)存中,其占用內(nèi)存無法被GC回收,導(dǎo)致內(nèi)存溢出。
注意,閉包的原理是作用域鏈,所以閉包訪問的上級作用域中的變量是個(gè)對象,其值為其運(yùn)算結(jié)束后的最后一個(gè)值。
3.執(zhí)行上下文
代碼運(yùn)行時(shí),產(chǎn)生一個(gè)對應(yīng)的執(zhí)行環(huán)境,這個(gè)叫做執(zhí)行上下文。
通常執(zhí)行上下文,有三個(gè)環(huán)境: 1.全局環(huán)境:代碼首先進(jìn)入的環(huán)境 2.函數(shù)環(huán)境:函數(shù)被調(diào)用時(shí)執(zhí)行的環(huán)境 3.eval函數(shù):www.cnblogs.com/chaoguo1234…
執(zhí)行上下文,可分為三個(gè)階段,分別為創(chuàng)建,執(zhí)行,銷毀階段。我們簡單的分析一下,各個(gè)階段分別處理了什么。
創(chuàng)建階段: (1).生成變量對象 (2).建立作用域鏈 (3).確定 this 指向
執(zhí)行階段:(1).變量賦值(2).函數(shù)引用(3).執(zhí)行其他代碼
銷毀階段:執(zhí)行完畢出棧,等待回收被銷毀
4.原型/原型鏈
指構(gòu)造函數(shù)的內(nèi)置屬性,即prototype屬性。每個(gè)構(gòu)造函數(shù)都自帶prototype屬性,指向一個(gè)對象,常用實(shí)例共享屬性和方法的。
Prototype.constructor會(huì)指向原構(gòu)造函數(shù)
對象的原型,也是個(gè)對象。只要對象的原型有值,不為null,他就還有原型。所以構(gòu)成了原型鏈。
5.作用鏈域
作用域鏈的原理和原型鏈很類似,如果這個(gè)變量在自己的作用域中沒有,那么它會(huì)尋找父級的,直到最頂層。注意:JS沒有塊級作用域,若要形成塊級作用域,可通過(function(){})();立即執(zhí)行的形式實(shí)現(xiàn)。
6.繼承
繼承的幾種方式:
1.原型鏈繼承本質(zhì)是重寫了對象。缺點(diǎn):1)對象實(shí)例共享所有繼承的屬性和方法
2)不能傳遞參數(shù)2.構(gòu)造函數(shù)繼承在子類構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。使用aapply()和call() 方法缺點(diǎn):1)函數(shù)復(fù)用性不高
2)只能繼承實(shí)例上的屬性,原型上的方法不可見3.組合繼承本質(zhì):原型鏈 + 構(gòu)造函數(shù)Parent.call(this) new Parent()避免了上述的缺點(diǎn),常用。優(yōu)點(diǎn):可傳參,不會(huì)與父類引用屬性共享缺點(diǎn):繼承父類函數(shù)的時(shí)候調(diào)用了父類構(gòu)造函數(shù),導(dǎo)致子類的原型上多了不需要的父類屬性,存在內(nèi)存上的浪費(fèi)。
4.原型式繼承實(shí)現(xiàn)本質(zhì):object()函數(shù)對傳入其中的對象執(zhí)行了一次淺復(fù)制
5.寄生式繼承借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法
6.寄生組合高效率只調(diào)用了一次構(gòu)造函數(shù),集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身,是實(shí)現(xiàn)基于類型繼承的最有效方式。就是將父類的原型賦值給了子類,并且將構(gòu)造函數(shù)設(shè)置為子類,這樣既解決了無用的父類屬性問題Parent.call + Object.create()
7.class繼承
7.this關(guān)鍵字
1) this總是指向函數(shù)的直接調(diào)用者(而非間接調(diào)用者)2) 如果有new關(guān)鍵字,this指向new出來的那個(gè)對象3) 在事件中,this指向目標(biāo)元素,特殊的是IE的attachEvent中的this總是指向全局對象window。
this大概有以下五種場景:1.綁定事件指向事件本身2.普通函數(shù)的,指向方法體。3.new函數(shù)的指向當(dāng)前類4.箭頭函數(shù),指向上級上下文5.call/apply/bind
8.new關(guān)鍵字
看以下代碼,這就是new的整體過程。
function createThis( proto ){var obj = new Object;obj.__proto__ = proto.prototype;let [ constructor, ...args] = [ ...arguments ];let result = constructor.apply( obj, args );return typeof result === 'object' ? result : obj; }可以從代碼中看到new的執(zhí)行過程,新建一個(gè)對象,設(shè)置原型鏈,改變this指向,根據(jù)對象返回結(jié)果。
9.類型的判斷
談到j(luò)s類型的判斷,我們能想起 typeof,instanceof,constructor,Object.prototype.toString.call()。(沒了吧?還有的話提醒我一下)
那么我們對比一下他們的作用與區(qū)別。
typeof?對于原始類型來說,除了 null 都可以顯示正確的類型。但是對于對象來說,除了函數(shù)都會(huì)顯示 object,所以他的作用,僅僅只能判斷原始類型,判斷不了對象。
instanceof,用于判斷一個(gè)變量是否某個(gè)對象的實(shí)例,內(nèi)部機(jī)制是通過原型鏈來判斷的。他的確能判斷是否類型的是否正確。但一點(diǎn)值得注意,instanceof 檢測的是原型,原型鏈上,每一個(gè)類型,都會(huì)返回true。所以,只能用來判斷兩個(gè)對象是否屬于實(shí)例關(guān)系, 而不能判斷一個(gè)對象實(shí)例具體屬于哪種類型。
constructor, 是原型prototype的一個(gè)屬性,當(dāng)函數(shù)被定義時(shí)候,js引擎會(huì)為函數(shù)添加原型prototype,并且這個(gè)prototype中constructor屬性指向函數(shù)引用, 因此重寫prototype會(huì)丟失原來的constructor。
但是他也有明顯的缺陷:
1:null 和 undefined 無constructor,這種方法判斷不了。2:還有,如果自定義對象,開發(fā)者重寫prototype之后,原有的constructor會(huì)丟失,因此,為了規(guī)范開發(fā),在重寫對象原型時(shí)一般都需要重新給 constructor 賦值,以保證對象實(shí)例的類型不被篡改。
toString是幾個(gè)方案中,相對比較不錯(cuò)的方案。建議使用。toString() 是 Object 的原型方法,調(diào)用該方法,默認(rèn)返回當(dāng)前對象的 [[Class]] 。這是一個(gè)內(nèi)部屬性,其格式為 [object Xxx] ,其中 Xxx 就是對象的類型。
10.類型的轉(zhuǎn)換
js類型的轉(zhuǎn)換,可以分為三種情況:
轉(zhuǎn)換為布爾值
轉(zhuǎn)換為數(shù)字
轉(zhuǎn)換為字符串
其中,轉(zhuǎn)化為boolean,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都轉(zhuǎn)為 true。我們?nèi)粘?梢杂盟鼇砼袛鄬ο笫欠裎促x值。
11.比較運(yùn)算符
比較運(yùn)算符,是我們常用到的。如果都為number類型,比較值的大小,那么當(dāng)然簡單咯。如果是非number值的時(shí)候如何處理呢?
順序如下:將值轉(zhuǎn)換為原始值(ToPrimitive方法)轉(zhuǎn)換為數(shù)字(valueOf方法)轉(zhuǎn)換為字符串(toString方法)
12.四則運(yùn)算符
這里筆者的記憶是這樣的,分為兩類:
加法類:只要有運(yùn)算有字符串,那么將全部轉(zhuǎn)為字符串。如果不是字符串(且數(shù)字),那就把它轉(zhuǎn)換為(字符串)或數(shù)字。
那么如何判斷先轉(zhuǎn)為數(shù)字還是轉(zhuǎn)為字符串呢?這涉及到加法運(yùn)算會(huì)觸發(fā)三種類型轉(zhuǎn)換。參考“比較運(yùn)算符”,ToPrimitive方法。
非加法類:只要其中一方是數(shù)字,那么另一方就轉(zhuǎn)為數(shù)字。
13.拷貝
拷貝,任何語言都有自己的深拷貝以及淺拷貝。深拷貝有利于數(shù)據(jù)的完全獨(dú)立,但是全是深拷貝的話,內(nèi)存又不會(huì)不斷的往上漲,于是又有了淺拷貝。
淺拷貝指拷貝引用對象,仍指向同一個(gè)地址,修改時(shí)原對象也會(huì)受到影響.。
深拷貝完全拷貝一個(gè)新對象,修改時(shí)原對象不再受到任何影響
基于內(nèi)存的節(jié)省,我們?nèi)粘S玫降暮瘮?shù),很多都屬于淺拷貝,比如我們的擴(kuò)展運(yùn)算符,還有Object.assign,contact,slice等。都屬于淺拷貝。
而深拷貝:
* 可以使用JSON.parse(JSON.stringify(obj))。性能最快。其弊端也必將明顯,首先無法拷貝函數(shù)、undefined、或symbol等值。其二對象要是有自身循環(huán)調(diào)用,會(huì)報(bào)錯(cuò)。 * 利用遞歸來實(shí)現(xiàn)每一層都重新創(chuàng)建對象并賦值 * 如何用jquery,可以考慮,$.extend( [deep ], target, object1 [, objectN ] ),這也是深拷貝的一種。 * 也可以利用lodash.js,cloneDeep方法進(jìn)行深拷貝。14.函數(shù)調(diào)用
js的函數(shù)調(diào)用,有四種方式:
1.方法調(diào)用模式(this指向他本身)
2.函數(shù)調(diào)用模式(this指向windows)
3.構(gòu)造器調(diào)用模式(利用原型構(gòu)造,JS摒棄這個(gè)方法)
4.apply調(diào)用模式(利用apply改變this對象。)
函數(shù)調(diào)用,自身攜帶的,記住有 this 和 arguments
15.高階函數(shù)
接收函數(shù)作為參數(shù)或者返回函數(shù)的函數(shù),都可成為高階函數(shù)。所以常見的方法有:map,filter,bind,apply等。
需要了解一下,高階函數(shù)實(shí)現(xiàn)AOP。
16.柯里化函數(shù)
柯里化,實(shí)現(xiàn)上,就是返回一個(gè)高階函數(shù),通過閉包把傳入的參數(shù)保存起來。當(dāng)傳入的參數(shù)數(shù)量不足時(shí),遞歸調(diào)用 bind 方法;數(shù)量足夠時(shí)則立即執(zhí)行函數(shù)。學(xué)習(xí)一下 javascript 的高階用法還是有意義的。
柯里化是一種將使用多個(gè)參數(shù)的一個(gè)函數(shù)轉(zhuǎn)換成一系列使用一個(gè)參數(shù)的函數(shù)的技術(shù)。
17.數(shù)組
數(shù)組的方法可以寫的實(shí)在是太多了。借助一下這位小伙伴的博客:juejin.im/post/684490…
18.偽數(shù)組
偽數(shù)組,說明它不是真正意義上的數(shù)組,他的輸出是個(gè)對象,但他的原型并不指向Array。
常見的偽數(shù)組包括:arguments、getElementsByTagName等獲取的NodeList對象
它的特性是:
1)具有l(wèi)ength屬性;
2)按索引方式存儲(chǔ)數(shù)據(jù);
3)沒有內(nèi)置方法,不具有數(shù)組的push()、pop()等方法
偽數(shù)組也可以轉(zhuǎn)換為數(shù)組,可以通過:
var args = Array.prototype.slice.call(arguments);
Array.from(arguments)
擴(kuò)展運(yùn)算符
19.重定向this
call,apply,bind,三者都是用來改變函數(shù)的this對象的指向的。且第一個(gè)參數(shù)都是this要指向的對象,也就是想指定的上下文。
但傳參的值也不同,apply后續(xù)只能傳遞數(shù)組,而call與bind可以傳遞多個(gè)參數(shù)。
bind 是返回對應(yīng)函數(shù),便于稍后調(diào)用;apply 、call 則是立即調(diào)用。
20.嚴(yán)格模式
use strict是否很熟悉?了解一下他的大概作用:1) 消除js不合理,不嚴(yán)謹(jǐn)?shù)胤?#xff0c;減少怪異行為2) 消除代碼運(yùn)行的不安全之處,3) 提高編譯器的效率,增加運(yùn)行速度4) 為未來的js新版本做鋪墊。
21.for循環(huán)
首先效率問題:for > forEach > map
如何選擇對應(yīng)的循環(huán)呢:
如果需要將數(shù)組按照某種規(guī)則映射為另一個(gè)數(shù)組 ? ?map
如果需要進(jìn)行簡單的遍歷 ??forEach 或者 for of
如果需要對迭代器進(jìn)行遍歷 ? ??for of
如果需要過濾出符合條件的項(xiàng) ? ?filter
此外,我們要明白傳統(tǒng)for
這個(gè) for-of 循環(huán)首先調(diào)用了 values 數(shù)組的 Symbol.iterator 方法,獲取了一個(gè)迭代器(對 Symbol.iterator 的調(diào)用發(fā)生在 JS 引擎后臺)。接下來 iterator.next() 被調(diào)用,迭代器結(jié)果對象的 value 屬性被讀出并放入了第一個(gè)結(jié)果變量。如果你只是簡單地迭代數(shù)組或集合的值,那么使用 for-of 循環(huán)而不是 for 循環(huán)就是個(gè)好主意。for-of 循環(huán)一般不易出錯(cuò),因?yàn)樾枰粢獾臈l件更少;傳統(tǒng)的 for 循環(huán)被保留用于處理更復(fù)雜的控制條件。在不可迭代對象、 null 或 undefined 上使用 for-of 語句,會(huì)拋出錯(cuò)誤。
二.前端基礎(chǔ)進(jìn)階
1)ES6篇
1.模塊化
在以前,js一直沒有模塊化的體系。這就會(huì)產(chǎn)生一個(gè)問題,當(dāng)項(xiàng)目到達(dá)大型時(shí),很大可能性出現(xiàn)方法重疊,以及安全性問題,成為大型項(xiàng)目的一個(gè)痛點(diǎn)與障礙。而es6模塊化正式為此誕生。
這里簡述前端模塊化的區(qū)別:
1)AMD, commonJS, 與es6,都屬于預(yù)加載類型。而后期引入的CDM是懶加載。何為預(yù)加載, 也就是說,在程序調(diào)用,所有的模塊都加載完成。而懶加載,是用到什么的時(shí)候,才去加載什么。
2)AMD跟cmd專注于前端的規(guī)范。而commonjs跟es6 moudle可用于前后端。
3)AMD的代表做為requirejs,cmd的代表作為seajs。commonjs 與 es6,則無需引入,只需要引入編譯器(如babel)即可。seajs為淘寶引入的規(guī)范,我們都知道淘寶相對很大,不采用懶加載,首屏的時(shí)間將會(huì)很長,不過現(xiàn)在已經(jīng)停止維護(hù)。
4)es6 跟 commonJS做了如下改變:
1.ES6只能新增值,無法重新賦值就會(huì)報(bào)錯(cuò)2.CommonJS 輸出是值的拷貝,即原來模塊中的值改變不會(huì)影響已經(jīng)加載的該值, ES6靜態(tài)分析,動(dòng)態(tài)引用,輸出的是值的引用,值改變,引用也改變,即原來模塊中的值改變則該加載的值也改變。3.CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。4.CommonJS 加載的是整個(gè)模塊,即將所有的接口全部加載進(jìn)來, ES6 可以單獨(dú)加載其中的某個(gè)接口(方法)。5.CommonJS this 指向當(dāng)前模塊,ES6 this指向undefined
2.變量聲明
變量聲明(var)會(huì)有變量提升。變量會(huì)提前初始化,也可以提前訪問。當(dāng)項(xiàng)目變量復(fù)雜的時(shí)候,很容易產(chǎn)生bug。es6就在這個(gè)時(shí)候,引入了let跟const。
當(dāng)然,引入let與const不僅僅解決了變量提升的問題,他們的不同如下:
1)局部作用域新引入的let,const聲明,再不會(huì)再產(chǎn)生變量提升。避免了變量提前訪問的場景,間接的提高了嚴(yán)謹(jǐn)性。我們可以在程序運(yùn)行時(shí)就知道了報(bào)錯(cuò),而非后期的調(diào)試中。
2)禁止重復(fù)聲明如果一個(gè)標(biāo)識符已經(jīng)在代碼塊內(nèi)部被定義,那么在此代碼塊內(nèi)使用同一個(gè)標(biāo)識符進(jìn)行 let 聲明就會(huì)導(dǎo)致拋出錯(cuò)誤
3)區(qū)分常量與變量這是let與const的區(qū)別。const 聲明會(huì)阻止對于變量綁定與變量自身值的修改,避免了我們?nèi)粘i_發(fā)中,了不小心改到常量的問題。
4)暫時(shí)性死區(qū)下述案例,用let跟var定義的結(jié)果,就明白什么叫暫時(shí)性死區(qū)
for( let i = 0; i<10; i++ ){setTimeOut( function(){alert(i );}, 1000); }3.Symbol
Symbol是JS新引入的基本類型。我們都知道在ES5之前,JS 已有的基本類型(字符串、數(shù)值、布爾類型、 null 與 undefined )之外, ES6 引入 了一種新的基本類型。
符號起初被設(shè)計(jì)用于創(chuàng)建對象私有成員,而這也是 JS 開發(fā)者期待已久的特性。在符號誕生之前,將字符串作為屬性名稱導(dǎo)致屬性可以被輕易訪問,無論命名規(guī)則如何。而“私有名稱”意味著開發(fā)者可以創(chuàng)建非字符串類型的屬性名稱,由此可以防止使用常規(guī)手段來探查這些名稱。
我們常用于:1.作為內(nèi)置屬性名稱。可以避免同參數(shù)名的覆蓋。2.使用Symbol來替代常量。Symbol來創(chuàng)建一些常量。比如訂單狀態(tài)等,可以也可以避免重復(fù)。
4.數(shù)組的擴(kuò)展
需要明白Array.of跟Array.form的意義。
首先上述提到,數(shù)組有了偽數(shù)組的概念,而轉(zhuǎn)化為數(shù)組,可以通過 Array.prototype.slice.call(arguments)。但是這個(gè)方法并不直觀,所以引入了更為直觀的Array.form。
只要是部署了iterator(下邊會(huì)提及)接口的數(shù)據(jù)結(jié)構(gòu),Array.from都能將其轉(zhuǎn)為數(shù)組。
而Array.of是為了解決new Array()的嚴(yán)謹(jǐn)性的問題。new Array( )后邊的值,可能代表長度,可能代表數(shù)值。
Array.of基本上可以用來替代Array()或newArray(),并且不存在由于參數(shù)不同而導(dǎo)致的重載,而且他們的行為非常統(tǒng)一。
5.函數(shù)的擴(kuò)展
es6對函數(shù)的擴(kuò)展,主要針對兩個(gè),一個(gè)是箭頭函數(shù),一個(gè)是解構(gòu)函數(shù)。
箭頭函數(shù)跟普通函數(shù)的區(qū)別:
(1)用了箭頭函數(shù),this就不是指向window,而是父級(指向是可變的)。
(2)不能使用arguments對象。
(3)不能用作構(gòu)造函數(shù),這就是說不能夠使用new命令,否則會(huì)拋出一個(gè)錯(cuò)誤。
(4)不可以使用yield命令,因此箭頭函數(shù)不能用作Generator函數(shù)
這里,簡單提及解構(gòu)函數(shù),解構(gòu)數(shù)組,以及字符串模版等概念。
6.Map,Set,WeakMap與WeakSet
數(shù)組在 JS 中的使用正如其他語言的數(shù)組一樣,但缺少更多類型的集合導(dǎo)致數(shù)組也經(jīng)常被當(dāng)作隊(duì)列與棧來使用。數(shù)組只使用了數(shù)值型的索引,而如果非數(shù)值型的索引是必要的,開發(fā)者便會(huì)使用非數(shù)組的對 象。
MapMap與Object,其最本質(zhì)的區(qū)別,鍵值對的集合(Hash 結(jié)構(gòu)),但是傳統(tǒng)上只能用字符串當(dāng)作鍵。
對于Map來說,undefined和null是兩個(gè)不同的鍵,布爾值true和字符串true是兩個(gè)不同的鍵,而NaN之間視為同一個(gè)鍵 ,0和-0也是一個(gè)鍵,
const map = new Map(); map.set(['a'], 1); map.get(['a'])會(huì)輸出underfined。
WeakMap
WeakMap跟Map結(jié)構(gòu)類似,也是用于生成鍵值對的集合,但是他只能用對象,來作為鍵值。其次,WeakMap的鍵名所指向的對象,不計(jì)入垃圾回收機(jī)制。
WeakMap 與 Map 在 API 上的區(qū)別主要是兩個(gè),一是沒有遍歷操作(即沒有keys()、values()和entries()方法),也沒有size屬性。因?yàn)闆]有辦法列出所有鍵名,某個(gè)鍵名是否存在完全不可預(yù)測,跟垃圾回收機(jī)制是否運(yùn)行相關(guān)。這一刻可以取到鍵名,下一刻垃圾回收機(jī)制突然運(yùn)行了,這個(gè)鍵名就沒了,為了防止出現(xiàn)不確定性,就統(tǒng)一規(guī)定不能取到鍵名。二是無法清空,即不支持clear方法。因此,WeakMap只有四個(gè)方法可用:get()、set()、has()、delete()。
WeakMap的實(shí)例比較少,個(gè)人從來沒有在實(shí)踐中使用。但有這么一個(gè)實(shí)例相對適合:比如我們要統(tǒng)計(jì)一個(gè)頁面統(tǒng)計(jì)該頁面所有節(jié)點(diǎn)的點(diǎn)擊次數(shù)。
其一,首先我們獲取到的dom是一個(gè)對象,符合作為鍵值。
其二,當(dāng)對應(yīng)的節(jié)點(diǎn)消失的時(shí)候,垃圾回收機(jī)制,回自動(dòng)回收對應(yīng)的在WeakMap節(jié)點(diǎn),同時(shí)達(dá)到釋放內(nèi)存的目的
SetSet可能相對更好理解,他可以簡單理解為是一個(gè)“無重復(fù)值”的“有序”列表,且運(yùn)行值方便快速訪問以及判斷。
我們可以利用他去重。包括數(shù)組,字符串等。
也可以利用他去接受一些具有 iterable 接口的其他數(shù)據(jù)結(jié)構(gòu),例如我們統(tǒng)計(jì)頁面有幾個(gè)div?new Set(document.querySelectorAll('div'));
WeakSet跟WeakMap類似,還是兩個(gè)關(guān)鍵字:“對象”,“內(nèi)存”。
7.iterator
迭代器iterator, 可以理解成一個(gè)為不同的數(shù)據(jù)結(jié)構(gòu),統(tǒng)一訪問的機(jī)制(Symbol.iterator屬性)。只要對應(yīng)的數(shù)據(jù)結(jié)構(gòu)有Symbol.iterator屬性,就可以完成遍歷操作。
function createIterator(items) {var i = 0;return {next: function() {var done = (i >= items.length);var value = !done ? items[i++] : undefined;return {done: done,value: value};}}; } var iterator = createIterator([1, 2, 3]); console.log(iterator.next()); // "{ value: 1, done: false }" console.log(iterator.next()); // "{ value: 2, done: false }" console.log(iterator.next()); // "{ value: 3, done: false }" console.log(iterator.next()); // "{ value: undefined, done: true }"我們的字符串,數(shù)組、類數(shù)組的對象、Set和Map,都具備Iterator接口。所以他們都是可迭代對象。
可迭代的作用有三個(gè):
1.為各種數(shù)據(jù)結(jié)構(gòu),提供一個(gè)統(tǒng)一的、簡便的訪問接口;
2.是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;
3.是ES6創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator接口主要供for...of消費(fèi)。
常用到iterator的場景包括:
1.for...of循環(huán)
2.擴(kuò)展運(yùn)算符
3.解構(gòu)賦值
4.yield_yield后面跟的是一個(gè)可遍歷的結(jié)構(gòu)
5.數(shù)組的遍歷會(huì)調(diào)用遍歷器接口
8.Generator
嚴(yán)格來說generator(生成器)屬于ES5,并不是ES6。但由于涉及迭代器等,所以并入es6模塊。
生成器( generator )是能返回一個(gè)迭代器的函數(shù)。生成器函數(shù)由放在 function 關(guān)鍵字之 后的一個(gè)星號( * )來表示,并能使用新的 yield 關(guān)鍵字。將星號緊跟在 function 關(guān)鍵 字之后,或是在中間留出空格,都是沒問題的.
形式上,Generator 函數(shù)是一個(gè)普通函數(shù),但是有兩個(gè)特征。一是,function關(guān)鍵字與函數(shù)名之間有一個(gè)星號;二是,函數(shù)體內(nèi)部使用yield表達(dá)式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)。
Generator有著"停止","開始"的狀態(tài),那我們可以用他來控制異步編程,所以,他也是異步的解決方案之一。
Generator要next一步一步往下執(zhí)行。如果想一步執(zhí)行,可以借助Thunk 函數(shù)(當(dāng)然他的原理也是遍歷幫我們執(zhí)行了next。)
9.Promise
Promise 被設(shè)計(jì)用于改善 JS 中的異步編程,與事件及回調(diào)函數(shù)對比,在異步操作方面為你提供了更多的控制權(quán)與組合性。Promise 調(diào)度被添加到 JS 引擎作業(yè)隊(duì)列,以便稍后執(zhí)行。不過此處有另一個(gè)作業(yè)隊(duì)列追蹤著 Promise 的完成與拒絕處理函數(shù),以確保適當(dāng)?shù)膱?zhí)行。
Promise 具有三種狀態(tài):掛起、已完成、已拒絕。一個(gè) Promise 起始于掛起態(tài),并在成功時(shí)轉(zhuǎn)為完成態(tài),或在失敗時(shí)轉(zhuǎn)為拒絕態(tài)。在這兩種情況下,處理函數(shù)都能被添加以表明Promise 何時(shí)被解決。
Promise的缺陷:
1)無法取消Promise,一旦新建它就會(huì)立即執(zhí)行,無法中途取消。
2)如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。
3)當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。
4)then的寫法相比await,明顯在程序代碼抒寫上,更加繁瑣。
10.proxy 跟 Reflect
proxy:代理對目標(biāo)對象進(jìn)行了虛擬,因此該代理與該目標(biāo)對象表面上可以被當(dāng)作同一個(gè)對象來對待。代理允許你攔截在目標(biāo)對象上的底層操作,而這原本是 JS 引擎的內(nèi)部能力。攔截行為使用了一個(gè)能夠響應(yīng)特定操作的函數(shù)(被稱為陷阱)。
Reflect:是給底層操作提供默認(rèn)行為的方法的集合,這些操作是能夠被代理重寫的。每個(gè)代理陷阱都有一個(gè)對應(yīng)的反射方法,每個(gè)方法都與對應(yīng)的陷阱函數(shù)同名,并且接收的參數(shù)也與之一致。
JS 運(yùn)行環(huán)境包含一些不可枚舉、不可寫入的對象屬性,然而在 ES5 之前開發(fā)者無法定義他們自己的不可枚舉屬性或不可寫入屬性。ES5引入了 Object.defineProperty() 方法以便開發(fā)者在這方面能夠像 JS 引擎那樣做。
ES6 讓開發(fā)者能進(jìn)一步接近 JS 引擎的能力,這些能力原先只存在于內(nèi)置對象上。語言通過代理( proxy )暴露了在對象上的內(nèi)部工作,代理是一種封裝,能夠攔截并改變 JS 引擎的底層操作。
11.Class寫法
Class寫法,可以簡單理解成ES6的一個(gè)語法糖。我們?nèi)粘S盟鶎?shí)現(xiàn)的功能,其實(shí)用ES5都可以做到,但是class的寫法,讓對象原型的寫法更加清晰。但不僅僅是糖語法。
1.首先Class的寫法會(huì)有特殊內(nèi)部屬性標(biāo)記[[FunctionKind]]:"classConstructor",這個(gè)標(biāo)記了,如果沒有new,則無法調(diào)用類構(gòu)造函數(shù)
2.類方法是不可枚舉的
3.Class是使用嚴(yán)格模式的。
此外,我們需要了解一下Class寫法中關(guān)鍵super、static、constructor、new.target。本文不做詳細(xì)介紹。
2)瀏覽器篇
1.瀏覽器的儲(chǔ)存
cookie,localStorage,sessionStorage.IndexedDB
比較一下差異:
1)傳遞方式:cookie在瀏覽器和服務(wù)器間來回傳遞;sessionStorage和localStorage不會(huì)自動(dòng)把數(shù)據(jù)發(fā)給服務(wù)器,僅在本地保存;
2)存儲(chǔ)大小:localStorage<=5M;sessionStorage<=5M;cookie<4K;(ie內(nèi)核瀏覽器占主流地位,且ie6仍占有相當(dāng)大的市場份額,所以在程序中應(yīng)當(dāng)使用少于20個(gè)cookie,且不大于4k)
3)有效性:localStorage:始終有效,窗口或?yàn)g覽器關(guān)閉也一直保存,因此用作持久數(shù)據(jù);sessionStorage:僅在當(dāng)前瀏覽器窗口關(guān)閉前有效,不能持久保持;cookie:只在設(shè)置的cookie過期時(shí)間之前一直有效,即使窗口或?yàn)g覽器關(guān)閉也不會(huì)消失;
4)共享機(jī)制:localStorage :在所有同源窗口中都是共享的;sessionStorage:同時(shí)“獨(dú)立”打開的不同窗口,即使是同一頁面,sessionStorage對象也是不同的;cookie:在所有同源窗口中都是共享的
5)瀏覽器支持:sessionStorage的瀏覽器最小版本:IE8、Chrome 5。
6)使用場景cookie:保存回話信息localStorage:持久保存的數(shù)據(jù)sessionStorage:擁有獨(dú)立特性的數(shù)據(jù)
2.瀏覽器的緩存
1.Service Worker 是運(yùn)行在瀏覽器背后的獨(dú)立線程。必須HTTPS。
三個(gè)步奏:注冊(下載:sw.js),監(jiān)聽(等其他worker失效),查看緩存1)sw線程能夠用來和服務(wù)器溝通數(shù)據(jù)(service worker的上下文內(nèi)置了fetch和Push API)2)能夠用來進(jìn)行大量復(fù)雜的運(yùn)算而不影響UI響應(yīng)。3)它能攔截所有的請求
2.Memory Cache將資源緩存在了內(nèi)存中。事實(shí)上,所有的網(wǎng)絡(luò)請求都會(huì)被瀏覽器緩存到內(nèi)存中,當(dāng)然,內(nèi)存容量有限,緩存不能無限存放在內(nèi)存中,因此,注定是個(gè)短期緩存。內(nèi)存緩存的控制權(quán)在瀏覽器,前后端都不能干涉。
3.Disk Cache存儲(chǔ)在硬盤中的緩存強(qiáng)緩存和協(xié)商緩存, HTTP Header 來實(shí)現(xiàn)的。Cache-Control > Expires(http1.0產(chǎn)物, 受本地時(shí)間影響) > ETag(http1.1出現(xiàn)) > Last-Modified(Last-Modified 打開文件的時(shí)候會(huì)變,以秒計(jì)算的)
4.Push Cache
服務(wù)器推送,http2
3.瀏覽器的渲染
生成dom樹:字節(jié)數(shù)據(jù)-->字符串-->標(biāo)記(token)-->node-->dom
生成css樹:字節(jié)數(shù)據(jù)-->字符串-->標(biāo)記(token)-->node-->cssdom
整體的渲染過程:
1)處理 HTML 并構(gòu)建 DOM 樹。
2)處理 CSS 構(gòu)建 CSSOM 樹。
3)將 DOM 與 CSSOM 合并成一個(gè)渲染樹。
4)根據(jù)渲染樹來布局,計(jì)算每個(gè)節(jié)點(diǎn)的位置。
5)調(diào)用 GPU 繪制,合成圖層,顯示在屏幕上。
兩個(gè)重要的概念,重繪與回流:
重繪:當(dāng)節(jié)點(diǎn)需要更改外觀而不會(huì)影響布局的,比如改變 color 就叫稱為重繪
回流:布局或者幾何屬性需要改變就稱為回流。回流必定會(huì)發(fā)生重繪,重繪不一定會(huì)引發(fā)回流。回流所需的成本比重繪高的多,改變深層次的節(jié)點(diǎn)很可能導(dǎo)致父節(jié)點(diǎn)的一系列回流。當(dāng) Event loop 執(zhí)行完 Microtasks 后,會(huì)判斷 document 是否需要更新。因?yàn)闉g覽器是 60Hz 的刷新率,每 16ms 才會(huì)更新一次。
導(dǎo)致性能問題:
1)改變 window 大小
2)改變字體
3)添加或刪除樣式
4)文字改變
5)定位或者浮動(dòng)
6)盒模型
減少重繪和回流的細(xì)節(jié):
1)使用 translate 替代 top
2)使用 visibility 替換 display: none ,因?yàn)榍罢咧粫?huì)引起重繪,后者會(huì)引發(fā)回流(改變了布局)
3)盡量算出結(jié)果再去重繪把 DOM 離線后修改,比如:先把 DOM 給 display:none (有一次 Reflow),然后你修改 100 次,然后再把它顯示出來
4)動(dòng)畫實(shí)現(xiàn)的速度的選擇,動(dòng)畫速度越快,回流次數(shù)越多,也可以選擇使用 requestAnimationFrame ?Load 和 DOMContentLoaded 區(qū)別。Load 事件觸發(fā)代表頁面中的 DOM,CSS,JS,圖片已經(jīng)全部加載完畢。DOMContentLoaded 事件觸發(fā)代表初始的 HTML 被完全加載和解析,不需要等待 CSS,JS,圖片加載。
4.瀏覽器的安全
1.xss跨站腳本攻擊原理:(1)構(gòu)造URL (2)發(fā)布內(nèi)容式 (3)蠕蟲式
2.CSRF跨站請求偽造1)驗(yàn)證碼。2)HTTP Referer是header的一部分 3)token
3.sql腳本注入拼接腳本
4.上傳漏洞
(1)檢查服務(wù)器是否判斷了上傳文件類型及后綴。(2) 定義上傳文件類型白名單,即只允許白名單里面類型的文件上傳。(3) 文件上傳目錄禁止執(zhí)行腳本解析,避免攻擊者進(jìn)行二次攻擊。
5.瀏覽器的跨域
首先什么是跨域,違反瀏覽器同源策略的就是跨域。跨域本身就是就是為了保護(hù)瀏覽器的安全, 主要是用來防止 CSRF 攻擊的
那什么是同源策略?所謂的同源,指的是協(xié)議,域名,端口相同。瀏覽器處于安全方面的考慮,只允許本域名下的接口交互,不同源的客戶端腳本,在沒有明確授權(quán)的情況下,不能讀寫對方的資源。
解決同源策略的方案:
1)sonp
2)iframe
3)postMessage
4)CORS
5)webscoket
6)反向代理服務(wù)器
6.瀏覽器的內(nèi)存
瀏覽器(通常指)的內(nèi)存分配,64位系統(tǒng)下大約為1.4GB,在32位系統(tǒng)下大約為0.7G。
我們通常定義變量時(shí)候就完成了分配內(nèi)存,使用時(shí)候是對內(nèi)存的讀寫操作,內(nèi)存的釋放依賴于瀏覽器的垃圾回收機(jī)制。
造成內(nèi)存泄露
1.意外的全局變量引起的內(nèi)存泄漏。
2.閉包引起的內(nèi)存泄漏
3.沒有清理的DOM元素引用
4.被遺忘的定時(shí)器或者回調(diào)
5.監(jiān)聽事件
7.瀏覽器的垃圾回收
64位下新生代的空間為64M,老生代為1400M32位下新生代的空間為16M,老生代為700M.
javaScript使用垃圾回收機(jī)制來自動(dòng)管理內(nèi)存,垃圾回收是一把雙刃劍
優(yōu)勢:可以大幅度簡化程序的內(nèi)存管理代碼,降低程序的負(fù)擔(dān),減少因時(shí)常運(yùn)轉(zhuǎn)而帶來的內(nèi)存泄露問題。
劣勢:意味著程序員將無法掌控內(nèi)存。js沒有暴露任何關(guān)于內(nèi)存的API。我們無法強(qiáng)迫其進(jìn)行垃圾回收,也無法干預(yù)內(nèi)存管理。
1、V8最初是為了瀏覽器設(shè)計(jì)的,不太可能遇到大內(nèi)存的場景2、js垃圾回收的時(shí)候程序會(huì)暫停線程執(zhí)行,會(huì)占用一定時(shí)間。
它有兩種情況會(huì)回收,一種是定時(shí)回收,一種內(nèi)存不夠了回收。
1.新生代算法Scavenge GC(GC 復(fù)制算法)分為兩個(gè)空間:form 跟 to。
2.老生代算法標(biāo)記清除算法標(biāo)記壓縮算法
對垃圾回收算法有興趣的朋友:www.jianshu.com/p/a8a04fd00…
8.瀏覽器的執(zhí)行機(jī)制
javascript是一門單線程語言, Event Loop是javascript的執(zhí)行機(jī)制libuv
需明白什么叫事件循環(huán)事件,微任務(wù),宏任務(wù)。以及如何運(yùn)行。
可了解:juejin.im/post/684490…
不知覺中,文章已來到了2W字。貌似掘金的限制是2W字?筆者決定分開多篇文章來匯總,避免有人關(guān)心下一章節(jié)的內(nèi)容,所以本文先給出大概菜單,預(yù)計(jì)時(shí)間一周以內(nèi),有興趣敬請關(guān)注!
三.鞏固前端基建
1)加深鞏固篇
1.前端去重的方法有哪些?
2.前端異步的方案有哪些?
3.前端網(wǎng)絡(luò)請求有哪些?
4.前端定時(shí)器有哪些?
5.前端創(chuàng)建對象有哪幾種方式?
6.前端代碼的復(fù)用有哪幾種方式?
2)工具拓展篇
1.wepback
2.nignx
3.csr與ssr
4.web Worker
3)網(wǎng)絡(luò)協(xié)議篇
TCP三次握手,DNS解析...
4)設(shè)計(jì)模式篇
單例模式,觀察者模式....
5)前端算法篇
排序算法等...
四.手寫原生代碼
apply, call, bind, new...
五.前端框架
1)Vue
mvvn,數(shù)據(jù)劫持,router,vuex...
2)React
redux,hooks...
3)微信小程序
自定義組件,生命周期...
4)hybrid app
六.前端性能
1)如何跟蹤
perfomance lighthouse...
2)如何優(yōu)化
從網(wǎng)絡(luò)出發(fā),從渲染出發(fā)...
七.前端素養(yǎng)
職業(yè)生涯規(guī)劃,對前端的看法...
最后
看完點(diǎn)個(gè)贊,分享一下吧,讓更多的朋友能夠看到。如果你喜歡前端開發(fā)博客的分享,就給公號標(biāo)個(gè)星吧,這樣就不會(huì)錯(cuò)過我的文章了。
好文和朋友一起看~
總結(jié)
以上是生活随笔為你收集整理的落魄前端,整理给自己的前端知识体系复习大纲(上篇,2w字)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用C# .net开发微信公众号之服务器
- 下一篇: 众昂矿业:萤石因奇特的“荧光效应”而得名