【精品】前端知識梳理
作者:廣東靚仔
一、前言
最近有小伙伴私聊廣東靚仔,能整理一份目前主流的前端知識點么?
因此有了這篇文章。
目錄
原型鏈
繼承
閉包
es6
this指向
事件循環(huán)
緩存相關
http相關
瀏覽器渲染相關
css相關
React源碼
vue源碼
算法和手寫編程題
性能優(yōu)化
webpack相關
git高級操作
前端微服務
設計模式
原型鏈
什么是原型?
任何對象實例都有一個原型,也叫原型對象,這個原型對象由對象的 內置屬性_proto_指向它的構造函數(shù)的 prototype 指向的對象,即任何對 象都是由一個構造函數(shù)創(chuàng)建的,但是不是每一個對象都有 prototype, 只有方法才有 prototype。
什么是原型鏈?
? ? 原型鏈基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。我們知道,每個構造函數(shù)都有一個原型對象,每個原型對象都 有一個指向構造函數(shù)的指針,而實例又包含一個指向原型對象的內部指 針。? ? 原型鏈的核心就是依賴對象的_proto_的指向,當自身不存在的屬性 時,就一層層的扒出創(chuàng)建對象的構造函數(shù),直至到 Object 時,就沒有 _proto_指向了。因為_proto_實質找的是 prototype,所以我們只要找這個鏈條上的構造 函數(shù)的 prototype。? ? 其中 Object.prototype 是沒有_proto_屬性的,它 ==null。每個構造函數(shù)都有一個原型對象,原型對象都包含一個指向構造函數(shù)的 指針,而實例都包含指向原型對象內部的指針。? ? 我們讓原型對象(1)等 于另一個原型對象的實例(2), 此時原型對象(2)將包含一個指向原型對象(1)的指針, 再讓原型對象(2)的實例等于原型對象(3),如此層層遞進就構成了實 例和原型的鏈條,這就是原型鏈的概念 每個構造函數(shù)都有一個原型對象,原型對象都包含一個指向構造函數(shù)想 指針(constructor),而實例對象都包含一個指向原型對象的內部指針 (__proto__)。如果讓原型對象等于另一個原型對象的實例,此時的原型 對象將包含一個指向另一個原型的指針(__proto__),另一個原型也包含 著一個指向另一個構造函數(shù)的指針(constructor)。假如另一個原型又是 另一個類型的實例……這就構成了實例與原型的鏈條。也叫原型鏈原型繼承?
原型繼承是 js 的一種繼承方式,原型鏈作為實現(xiàn)繼承的主要方法,其基本 思路是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。原型繼承:利用原型中的成員可以被和其相關的對象共享這一特性,可 以實現(xiàn)繼承,這種實現(xiàn)繼承的方式,就叫做原型繼承。繼承
繼承有六種
原型繼承
原型繼承是 js 的一種繼承方式,原型鏈作為實現(xiàn)繼承的主要方法,其基本 思路是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法, 原型繼承:利用原型中的成員可以被和其相關的對象共享這一特性,可 以實現(xiàn)繼承,這種實現(xiàn)繼承的方式,就叫做原型繼承特點:- 非常純粹的繼承關系,實例是子類的實例,也是父類的實例
- 父類新增原型方法/原型屬性,子類都能訪問到
- 簡單,易于實現(xiàn)
缺點:
- 要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之后執(zhí)行,不能放到構造器中
- 無法實現(xiàn)多繼承
- 來自原型對象的所有屬性被所有實例共享(來自原型對象的引用屬性是所有實例共享的)
- 創(chuàng)建子類實例時,無法向父類構造函數(shù)傳參
借用構造函數(shù)繼承
使用父類的構造函數(shù)來增強子類實例,等于是復制父類的實例屬性給子類(沒用到原型)
特點:
- 解決了1中,子類實例共享父類引用屬性的問題
- 創(chuàng)建子類實例時,可以向父類傳遞參數(shù)
- 可以實現(xiàn)多繼承(call多個父類對象)
缺點:
- 實例并不是父類的實例,只是子類的實例
- 只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
- 無法實現(xiàn)函數(shù)復用,每個子類都有父類實例函數(shù)的副本,影響性能
組合繼承
核心:通過調用父類構造,繼承父類的屬性并保留傳參的優(yōu)點,然后通過將父類實例作為子類原型,實現(xiàn)函數(shù)復用特點:
- 彌補了方式2的缺陷,可以繼承實例屬性/方法,也可以繼承原型屬性/方法
- 既是子類的實例,也是父類的實例
- 不存在引用屬性共享問題
- 可傳參
- 函數(shù)可復用
缺點:
- 調用了兩次父類構造函數(shù),生成了兩份實例(子類實例將子類原型上的那份屏蔽了)
原型式繼承
寄生式繼承
寄生組合式繼承
核心:通過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點
閉包
什么是閉包?
閉包可以簡單理解成:定義在一個函數(shù)內部的函數(shù)。其中一個內部函數(shù) 在包含它們的外部函數(shù)之外被調用時,就會形成閉包。閉包的特點?
特點:1.函數(shù)嵌套函數(shù)。2.函數(shù)內部可以引用外部的參數(shù)和變量。3.參數(shù)和變量不會被垃圾回收機制回收使用:1.讀取函數(shù)內部的變量;2.這些變量的值始終保持在內存中,不會在外層函數(shù)調用后被自動清除優(yōu)點:1:變量長期駐扎在內存中;2:避免全局變量的污染;3:私有成員的存在 ; 缺點:會造成內存泄露JS 的閉包
閉包是指有權訪問另外一個函數(shù)作用域中的變量的函數(shù)。閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會繼 續(xù)存在。閉包就是就是函數(shù)的“堆?!痹诤瘮?shù)返回后并不釋放,我們 也可以理解為這些函數(shù)堆棧并不在棧上分配而是在堆上分配。當在一 個函數(shù)內定義另外一個函數(shù)就會產生閉包。為什么要用??匿名自執(zhí)行函數(shù):我們知道所有的變量,如果不加上 var 關鍵字,則 默認的會添加到全局對象的屬性上去,這樣的臨時變量加入全局對象 有很多壞處,比如:別的函數(shù)可能誤用這些變量;造成全局對象過于 龐大,影響訪問速度(因為變量的取值是需要從原型鏈上遍歷的)。除 了每次使用變量都是用 var 關鍵字外,我們在實際情況下經(jīng)常遇到 這樣一種情況,即有的函數(shù)只需要執(zhí)行一次,其內部變量無需維護, 可以用閉包。es6
Let 與 var 與 const 的區(qū)別?
Var 聲明的變量會掛載在 window 上,而 let 和 const 聲明的變量不會?Var 聲明的變量存在變量提升,let 和 const 不存在變量提升 同一作用域下 var 可以聲明同名變量,let 和 const、不可以 Let 和 const 聲明會形成塊級作用域Let 暫存死區(qū)Const 一旦聲明必須賦值,不能用 null 占位,聲明后不能再修改,如果 聲明的是復合類型數(shù)據(jù),可以修改屬性,簡單理解就是:const定義的常量是基本數(shù)據(jù)類型的時候不可以被更改const定義的常量是引用數(shù)據(jù)類型的時候,其值可以被更改。
數(shù)組方法有哪些?
push() 從后面添加元素,返回值為添加完后的數(shù)組的長度arr.pop() 從后面刪除元素,只能是一個,返回值是刪除的元素arr.shift() 從前面刪除元素,只能刪除一個 返回值是刪除的元素arr.unshift() 從前面添加元素, 返回值是添加完后的數(shù)組的長度arr.splice(i,n) 刪除從 i(索引值)開始之后的那個元素。返回值是刪除的元 素arr.concat() 連接兩個數(shù)組 返回值為連接后的新數(shù)組str.split() 將字符串轉化為數(shù)組arr.sort() 將數(shù)組進行排序,返回值是排好的數(shù)組,默認是按照最左邊的數(shù) 字進行排序,不是按照數(shù)字大小排序的arr.reverse() 將數(shù)組反轉,返回值是反轉后的數(shù)組arr.slice(start,end) 切去索引值 start 到索引值 end 的數(shù)組,不包含 end 索引的值,返回值是切出來的數(shù)組arr.forEach(callback) 遍歷數(shù)組,無 return 即使有 return,也不會返回 任何值,并且會影響原來的數(shù)組arr.map(callback) 映射數(shù)組(遍歷數(shù)組),有 return 返回一個新數(shù)組 。arr.filter(callback) 過濾數(shù)組,返回一個滿足要求的數(shù)組普通函數(shù)和構造函數(shù)的區(qū)別?
1.構造函數(shù)也是一個普通函數(shù),創(chuàng)建方式和普通函數(shù)一樣,但是構造函數(shù) 習慣上首字母大寫2.調用方式不一樣,普通函數(shù)直接調用,構造函數(shù)要用關鍵字 new 來調 用3.調用時,構造函數(shù)內部會創(chuàng)建一個新對象,就是實例,普通函數(shù)不會創(chuàng) 建新對象4.構造函數(shù)內部的 this 指向實例,普通函數(shù)內部的 this 指向調用函數(shù)的 對象(如果沒有對象調用,默認為 window)5.構造函數(shù)默認的返回值是創(chuàng)建的對象(也就是實例),普通函數(shù)的返回 值由 return 語句決定6.構造函數(shù)的函數(shù)名與類名相同Promise 的理解?
promise 有三種狀態(tài):pending 初始狀態(tài)也叫等待狀態(tài),fulfiled 成功狀態(tài),rejected 失敗狀態(tài);狀態(tài)一旦改變,就不會再變Promise 的兩個特點:1、Promise 對象的狀態(tài)不受外界影響2、Promise 的狀態(tài)一旦改變,就不會再變,任何時候都可以得到這個結果,狀態(tài)不可以逆,Promise 的三個缺點:1)無法取消 Promise,一旦新建它就會立即執(zhí)行,無法中途取消2)如果不設置回調函數(shù),Promise 內部拋出的錯誤,不會反映到外部3)當處于 pending(等待)狀態(tài)時,無法得知目前進展到哪一個階段, 是剛剛開始還是即將完成async 的用法?
Async 就是 generation 和 promise 的語法糖,async 就是將 generator 的*換成 async,將 yiled 換成 await 函數(shù)前必須加一個 async,異步操作方法前加一個 await 關鍵字,意思就 是等一下,執(zhí)行完了再繼續(xù)走,注意:await 只能在 async 函數(shù)中運行, 否則會報錯 Promise 如果返回的是一個錯誤的結果,如果沒有做異常處理,就會報 錯,所以用 try..catch 捕獲一下異常就可以了this指向
this指向是什么?
this 通常指向的是我們正在執(zhí)行的函數(shù)本身,或者是, 指向該函數(shù)所屬的對象。全局的 this → 指向的是 Window對象中的 this → 指向其本身事件中 this → 指向事件對象改變函數(shù)內部 this 指針的指向函數(shù)(bind,apply,call 的區(qū) 別)
通過 apply 和 call 改變函數(shù)的 this 指向。他們兩個函數(shù)的第一個 參數(shù)都是一樣的表示要改變指向的那個對象,第二個參數(shù),apply 是 數(shù)組,而 call 則是 arg1,arg2...這種形式。通過 bind 改變 this 作 用域會返回一個新的函數(shù),這個函數(shù)不會馬上執(zhí)行實現(xiàn)一個 bind 函數(shù)
原理:通過 apply 或者 call 方法 來實現(xiàn)。
Function.prototype.bind=function(obj,arg){
????var?arg?=?Array.prototype.slice.call(arguments,1);
????var?context?=?this;
????var?bound=function(newArg){
????????arg=arg.co?ncat(Array.prototype.slice.call(newArg)?);
????????return?context.apply(obj,arg);
????}
????var?F=function(){}
????//?這里需要一個寄生組?合繼承
????F.prototype=context.prototype;?
????bound.prototype=new?F();
????return?bound;
}
事件循環(huán)
JavaScript 是一門單線程語言,異步操作都是放到事件循環(huán)隊列里面,等待主執(zhí)行棧來執(zhí)行的,并沒有專門的異步執(zhí)行線程。同步和異步任務分別進入不同的執(zhí)行環(huán)境,同步的進入主線程,即主執(zhí)行棧,異步的進入任務隊列。主線程內的任務執(zhí)行完畢為空,會去任務隊列讀取對應的任務,推入主線程執(zhí)行。關鍵的步驟1.在此次 tick 中選擇最先進入隊列的任務( oldest task ),如果有則執(zhí)行(一次)2.檢查是否存在 Microtasks ,如果存在則不停地執(zhí)行,直至清空Microtask Queue3.更新 render宏任務主要包含:script( 整體代碼)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 環(huán)境)微任務主要包含:Promise、MutaionObserver、process.nextTick(Node.js 環(huán)境)microtask 優(yōu)先于 task 執(zhí)行緩存相關
本地存儲與 cookie 的區(qū)別
Cookie 是小甜餅的意思。顧名思義,cookie 確實非常小,它的大小限 制為 4KB 左右。它的主要用途有保存登錄信息,比如你登錄某個網(wǎng)站市 場可以看到“記住密碼”,這通常就是通過在 Cookie 中存入一段辨別用 戶身份的數(shù)據(jù)來實現(xiàn)的localStoragelocalStorage 是 HTML5 標準中新加入的技術,它并不是什么劃時代的 新東西。早在 IE 6 時代,就有一個叫 userData 的東西用于本地存儲, 而當時考慮到瀏覽器兼容性,更通用的方案是使用 Flash。而如今, localStorage 被大多數(shù)瀏覽器所支持,如果你的網(wǎng)站需要支持 IE6+, 那以 userData 作為你方案是種不錯的選擇sessionStoragesessionStorage 與 localStorage 的接口類似,但保存數(shù)據(jù)的生命周期 與 localStorage 不同。做過后端開發(fā)的同學應該知道 Session 這個詞 的意思,直譯過來是“會話”。而 sessionStorage 是一個前端的概念, 它只是可以將一部分數(shù)據(jù)在當前會話中保存下來,刷新頁面數(shù)據(jù)依舊存 在。但當頁面關閉后,sessionStorage 中的數(shù)據(jù)就會被清空。三者的異同特性Cookie localStorage sessionStorage 數(shù)據(jù)的生命期 一般由服務器生成,可設置失效時間。如果在瀏覽器端生成 Cookie,默 認是關閉瀏覽器后失效 除非被清除,否則永久保存 僅在當前會話下有效,關閉頁面或瀏覽器后被清除存放數(shù)據(jù)大小4K 左右 一般為 5MB 與服務器端通信 每次都會攜帶在 HTTP 頭中,如果使用 cookie 保存過多數(shù)據(jù)會帶來性能 問題僅在客戶端(即瀏覽器)中保存,不參與和服務器的通信 易用性 需要程序員自己封裝,源生的 Cookie 接口不友好 源生接口可以接受,亦可再次封裝來對 Object 和 Array 有更好的支持http相關
http特性
HTTP0.9 特性
- 沒有請問頭和請求體只有請求行
- 只能發(fā)送html文件
HTTP1.0 特性
- 可以發(fā)送javaScript、CSS、圖片、音頻
- 加上請求頭和請求體
- 狀態(tài)碼
- cache 機制可傳參
- 每進行一次 HTTP 通信,都需要經(jīng)歷建立 TCP 連接、傳輸 HTTP 數(shù)據(jù)和斷開 TCP 連接三個階段
HTTP1.1 特性
- 持久連接的方法,它的特點是在一個 TCP 連接上可以傳輸多個 HTTP 請求,只要瀏覽器或者服務器沒有明確斷開連接,那么該 TCP 連接會一直保持(提高性能)
- 持久連接雖然能減少 TCP 的建立和斷開次數(shù),但是它需要等待前面的請求返回之后,才能進行下一次請求。如果 TCP 通道中的某個請求因為某些原因沒有及時返回,那么就會阻塞后面的所有請求,這就是著名的隊頭阻塞的問題(在 HTTP 1.1 中,每一個鏈接都默認是長鏈接,因此對于同一個 TCP 鏈接,HTTP 1.1 規(guī)定:服務端的響應返回順序需要遵循其接收到相應的順序。但這樣存在一個問題:如果第一個請求處理需要較長時間,響應較慢,將會“拖累”其他后續(xù)請求的響應,這是一種隊頭阻塞。)
- 引入了 Cookie、虛擬主機的支持、對動態(tài)內容的支持
- 瀏覽器為每個域名最多同時維護 6 個 TCP 持久連接(提高性能)
- 使用 CDN 的實現(xiàn)域名分片機制。(提高性能)
- 對帶寬的利用率卻并不理想(tcp 啟動慢、頭部堵塞、tcp 競爭)
HTTP2 特點
- 只使用一個 TCP 長連接來傳輸數(shù)據(jù),實現(xiàn)資源的并行請求,也就是任何時候都可以將請求發(fā)送給服務器,解決頭部堵塞(多路復用)
- 二進制傳輸
多路復用(原理二進制分幀層,攜帶id的幀流到服務器)
頭部壓縮
頭部被壓縮,減少了數(shù)據(jù)傳輸
服務端推送
有了二進制分幀層還能夠實現(xiàn)請求的優(yōu)先級、服務器推送、頭部壓縮等特性,從而大大提升了文件傳輸效率
但是HTTP2還是會存在 tcp 堵塞(理解,http 堵塞就是需要等待前面的http包發(fā)送完成而造成的等待,tcp 堵塞是TCP 傳輸過程中,由于單個數(shù)據(jù)包的丟失而造成的阻塞)
HTTP3
QUIC 看成是集成了“TCP+HTTP/2 的多路復用 +TLS 等功能
TCP與UDP的區(qū)別
1、基于連接與無連接;
2、對系統(tǒng)資源的要求(TCP較多,UDP少);
3、UDP程序結構較簡單;
4、流模式與數(shù)據(jù)報模式 ;
5、TCP保證數(shù)據(jù)正確性,UDP可能丟包;
6、TCP保證數(shù)據(jù)順序,UDP不保證。
TCP 握手過程
- 建立tcp鏈接(三次握手,客戶端發(fā)送 syn=j 給服務端然后處于 syn_send 狀態(tài);
- 服務端接受到syn,然后發(fā)送自己的syn包syn=k,和 ack=j+1(確認客戶端包),狀態(tài)為 syn_recv;
客戶端收到ack和syn則發(fā)送 ack=k+1給服務端表示確認,服務端和客戶端都進入了establish狀態(tài)),
為什么要3次握手:確認客戶端的接收、發(fā)送能力正常,服務器自己的發(fā)送、接收能力也正常
HTTP 緩存
強緩存(瀏覽器內部完成)max-age:數(shù)值,單位是秒,從請求時間開始到過期時間之間的秒數(shù)。基于請求時間(Date字段)的相對時間間隔,而不是絕對過期時間expires:和max-age一樣指緩存過期時間,但是他的指定了具體時間GMT格式,HTTP/1.1,Expire已經(jīng)被Cache-Control替代,原因在于Expires控制緩存的原理是使用客戶端的時間與服務端返回的時間做對比,那么如果客戶端與服務端的時間因為某些原因(例如時區(qū)不同;客戶端和服務端有一方的時間不準確)發(fā)生誤差,那么強制緩存則會直接失效,這樣的話強制緩存的存在則毫無意義協(xié)商緩存(需要詢問服務器)Last-Modified/If-Modified-Since(服務端時間對比):本地文件在服務器上的最后一次修改時間。緩存過期時把瀏覽器端緩存頁面的最后修改時間發(fā)送到服務器去,服務器會把這個時間與服務器上實際文件的最后修改時間進行對比,如果時間一致,那么返回304,客戶端就直接使用本地緩存文件。(瀏覽器最后修改時候和服務端對比,如果一致則走緩存)
問題:1. 現(xiàn)在大多數(shù)服務端都采用了負載均衡策略,可能導致不同虛擬主機返回的Last-Modified時間戳不一致,導致對比失敗~2. 文件也許會周期性的更改,但是他的內容并不改變,不希望客戶端重新getEtag/If-None-Match:(EntityTags,內容摘要)是URL的tag,用來標示URL對象是否改變,一般為資源實體的哈希值。和Last-Modified類似,如果服務器驗證資源的ETag沒有改變(該資源沒有更新),將返回一個304狀態(tài)告訴客戶端使用本地緩存文件。Etag的優(yōu)先級高于Last-Modified,Etag主要為了解決 Last-Modified無法解決的一些問題。
文件緩存策略1. 有文件指紋:index.html 用不用緩存,其他用強緩存+文件指紋2. 無指紋:index.html 用不用緩存,其他用協(xié)商etag緩存(文件變了就緩存)
瀏覽器渲染相關
一個頁面從輸入 URL 到頁面加載顯示完成,這個過程中都 發(fā)生了什么?
1、HTTP 請求準備階段
- 構建請求--瀏覽器構建請求行信息,準備發(fā)起網(wǎng)絡請求 GET /index.html HTTP1.1
查找緩存--如果瀏覽器發(fā)現(xiàn)請問資源在瀏覽器中存在副本,根據(jù)強緩存規(guī)則,如沒有過期那么直接返回資源,如何查找失敗進入下一個環(huán)節(jié):
--準備 ip 地址和端口
--DNS(域名和ip的映射系統(tǒng)) 域名解析,拿到ip之后找端口,默認為80
--建立tcp鏈接(三次握手)
--如果是https 還需要建立TLS連接
2、HTTP 發(fā)送請求
瀏覽器向服務端發(fā)起http請求,把請求頭和請求行一起發(fā)送個服務器,服務端解析請求頭如發(fā)現(xiàn)cache-control和etag(if-none-match),if-modified(if-modified-since)字段就會判斷緩存是否過期,如果沒有返回304,否則返回2003、HTTP 響應返回
- 瀏覽器拿到響應數(shù)據(jù),首先判斷是否是4XX或者5XX是就報錯,如果是3XX就重定向,2XX就開始解析文件,如果是gzip就解壓文件
- TCP斷開連接
4次揮手
瀏覽器解析渲染
建立根據(jù)html建立dom樹和css樹,如果遇到script首選判斷是否defer和async否則會阻塞渲染并編譯執(zhí)行js,如果沒有則組合生成render tree,最后瀏覽器開啟GPU進行繪制合成圖層,將內容顯示屏幕。
css相關
畫一條 0.5px 的線
方式一:采用 meta viewport 的方 式方式二:采用 border-image 的方 式 采用 transform: scale() 的方式css盒子模型
margin、border、padding\content默認情況盒子的width和height設置只是跟content的寬高真正寬:內容寬度+左右填充+左右邊距+左右邊框真正的高:內容高度+上下填充+上下邊距+上下邊框
css3新特性
邊框:border-radios 添加圓角邊框border-shadow:給框添加陰影 (水平位移,垂直位移,模糊半徑,陰 影尺寸,陰影顏色,insetr(內/外部陰影))border-image:設置邊框圖像border-image-source 邊框圖片的路徑border-image-slice 圖片邊框向內偏移border-image-width 圖片邊框的寬度border-image-outset 邊框圖像區(qū)域超出邊框的量border-image-repeat 圖像邊框是否平鋪(repeat 平鋪 round 鋪滿 stretch 拉伸)背景:Background-size 背景圖片尺寸Background-origin規(guī)定background-position屬性相對于什么位置定位Background-clip 規(guī)定背景的繪制區(qū)域(padding-box,border-box, content-box)漸變:Linear-gradient()線性漸變Radial-gradient()徑向漸變文本效果:Word-break:定義如何換行Word-wrap:允許長的內容可以自動換行Text-overflow:指定當文本溢出包含它的元素,應該干啥Text-shadow:文字陰影(水平位移,垂直位移,模糊半徑,陰影顏色)轉換:Transform 應用于 2D3D 轉換,可以將元素旋轉,縮放,移動,傾斜Transform-origin 可以更改元素轉換的位置,(改變 xyz 軸)Transform-style 指定嵌套元素怎么樣在三位空間中呈現(xiàn)2D 轉換方法:rotate 旋轉 translate(x,y)指定元素在二維空間的位移 scale(n) 定義縮放轉換3D 轉換方法:Perspective(n)為 3D 轉換 translate rotate scale過渡:Transition-proprety 過渡屬性名Transition-duration 完成過渡效果需要花費的時間Transition-timing-function 指定切換效果的速度Transition-delay 指定什么時候開始切換效果動畫:animation Animation-name 為@keyframes 動畫名稱animation-duration 動畫需要花費的時間animation-timing-function 動畫如何完成一個周期animation-delay 動畫啟動前的延遲間隔animation-iteration-count 動畫播放次數(shù)animation-direction 是否輪流反向播放動畫JS 動畫和 css3 動畫的差異性
渲染線程分為 main thread 和 compositor thread,如果 css 動畫 只 改 變 transform 和 opacity , 這 時 整 個 CSS 動 畫 得 以 在 compositor trhead 完成(而 JS 動畫則會在 main thread 執(zhí)行, 然后出發(fā) compositor thread 進行下一步操作),特別注意的是如果 改變 transform 和 opacity 是不會 layout 或者 paint 的。區(qū)別:功能涵蓋面,JS 比 CSS 大 實現(xiàn)/重構難度不一,CSS3 比 JS 更加簡單,性 能跳優(yōu)方向固定對幀速表現(xiàn)不好的低版本瀏覽 器,css3 可以做到自然降級 css 動畫有天然事件支持 css3 有兼容性問題? ??React源碼
react 組件之間的數(shù)據(jù)傳遞
正向傳值用 props 逆向傳值用函數(shù)傳值 通過事件調用函數(shù)傳遞 同級傳值用 pubsub-js 用 pubsub.publish(事件名,數(shù)據(jù))拋出數(shù)據(jù) 用 pubsub.subscribe(監(jiān)聽的事件,()=){})接收數(shù)據(jù) 跨組件傳遞 用 context 要使用 context 進行跨組件傳值就需要使用 createContext() 方 法 , 這 個 方 法 有 兩 個 對 象 provider 生 產者 Consumer 消費者調用 setState 之后發(fā)生了什么
React 在調用 setstate 后,react 會將傳入的參數(shù)對象和組件當前的狀態(tài) 合并,觸發(fā)調和過程, 在調和過程中,react 會根據(jù)新的狀態(tài)構建 react 元素樹重新渲染整個 UI 界面,在得到元素樹之后,react 會自動計算新老節(jié)點的差異,根據(jù)差 異對界面進行最小化重新渲染react 生命周期函數(shù)
componentWillMount 組件渲染之前調用componentDidMount 在第一次渲染之后調用componentWillReceiveProps 在組件接收到一個新的 props 時調用shouldComponentUpdate 判斷組件是否更新 htmlcomponentWillupdate 組件即將更新 html 時調用componentDidupdate 在組件完成更新后立即調用componentWillUnmount 在組件移除之前調用
為什么虛擬 dom 會提高性能?
虛擬 dom 相當于在 js 和真實 dom 中間加了一個緩存,利用 dom diff 算法避免了沒有必要的 dom 操作,從而提高性能請簡述虛擬 dom 與 diff 算法
虛擬DOM也就是常說的虛擬節(jié)點,它是通過js的object對象模擬DOM 中的節(jié)點,然后再通過特定的渲染方法將其渲染成真實的 DOM 節(jié)點。頻繁的操作 DOM,或大量造成頁面的重繪和回流Diff 算法:把樹形結構按照層級分解,只比較同級元素,給列表結構的 每個單元添加唯一的 key 值,方便比較diff 原理
tree diff web UI 中 dom 節(jié)點跨層級的移動操作特別少,可以忽略不計component diff 擁有相同類的兩個組件將會生成相似的樹形結構,擁有 不同類的兩個組件會生成不同的樹形結構element diff 對于同一層級的一組子節(jié)點,他們可以通過唯一的 id 進行 區(qū)分
何為高階組件(higher order component)?
高階組件是一個以組件為參數(shù)并返回一個新組件的函數(shù)。HOC 運行你重用代碼、邏輯和引導抽象。最常見的可能是 Redux 的 connect 函數(shù)。除了簡單分享工具庫和簡單的組合,HOC 最好 的方式是共享 React 組件之間的行為。如果你發(fā)現(xiàn)你在不同的 地方寫了大量代碼來做同一件事時,就應該考慮將代碼重構為可 重用的 HOC。vue源碼
vue 中 keep-alive 的理解?
概念:keep-alive 是 vue 的內置組件,當它動態(tài)包裹組件時,會緩存不 活動的組件實例,它自身不會渲染成一個 DOM 元素也不會出現(xiàn)在父組 件鏈中?作用:在組件切換過程中將狀態(tài)保留在內存中,防止重復渲染 DOM,減 少加載時間以及性能消耗,提高用戶體驗。生命周期函數(shù):Activated 在 keep-alive 組件激活時調用,deactivated 在 keep-alive 組件停用時調用Vue 組件中的 data 為什么是函數(shù)
Data 是一個函數(shù)時,每個組件實例都有自己的作用域,每個實例相互獨 立,不會相互影響如果是引用類型(對象),當多個組件共用一個數(shù)據(jù)源時,一處數(shù)據(jù)改變, 所有的組件數(shù)據(jù)都會改變,所以要利用函數(shù)通過 return 返回對象的拷貝, (返回一個新數(shù)據(jù)),讓每個實例都有自己的作用域,相互不影響。組件中寫 name 選項有什么作用?
項目使用 keep-alive 時,可搭配組件 name 進行緩存過濾DOM 做遞歸組件時需要調用自身 namevue-devtools 調試工具里顯示的組見名稱是由vue中組件name決定的Vue 雙向綁定的原理
Vue2 雙向綁定就是:數(shù)據(jù)變化更新視圖,視圖變化更新數(shù)據(jù) Vue 數(shù)據(jù)雙向綁定是通過數(shù)據(jù)劫持和觀察者模式來實現(xiàn)的, 數(shù)據(jù)劫持,object.defineproperty 它的目的是:當給屬性賦值的時候, 程序可以感知到,就可以控制改變屬性值 觀察者模式 當屬性發(fā)生改變的時候,使用該數(shù)據(jù)的地方也發(fā)生改變vue3使用了proxy。proxy優(yōu)點:1、直接監(jiān)聽對象而非屬性2、直接監(jiān)聽數(shù)組的變化3、攔截的方式有很多種(有13種,set,get,has)4、Proxy返回一個新對象,可以操作新對象達到目的proxy缺點:1、 proxy有兼容性問題,不能用polyfill來兼容(polyfill主要撫平不同瀏覽器之間對js實現(xiàn)的差異)說說對 proxy 的理解
vue 的數(shù)據(jù)劫持有兩個缺點: 1、無法監(jiān)聽通過索引修改數(shù)組的值的變化 2、無法監(jiān)聽 object 也就是對象的值的變化所以 vue2.x 中才會有 $set 屬性的存在proxy 是 es6 中推出的新 api,可以彌補以上兩個缺點,所以 vue3.x 版本用 proxy 替換 object.defineproperty
計算屬性與 watch 區(qū)別
Computed watch 區(qū)別就是 computed 的緩存功能,當無關數(shù)據(jù)數(shù) 據(jù)改變時,不會重新計算,直接使用緩存中的值。計算屬性是用來聲明 式的描述一個值依賴了其他的值,當所依賴的值后者變量發(fā)生變化時, 計算屬性也跟著改變, Watch 監(jiān)聽的是在 data 中定義的變量,當該變量變化時,會觸發(fā) watch 中的方法Route 與 router 區(qū)別
1. router 是 VueRouter 的一個對象,通過 Vue.use(VueRouter)和 VueRouter 構造函數(shù)得到一個 router 的實例對象,這個對象中是一個全 局的對象,他包含了所有的路由包含了許多關鍵的對象和屬性。2.route 是一個跳轉的路由對象,每一個路由都會有一個 route 對象,是 一個局部的對象,可以獲取對應的 name,path,params,query 等Vue 的 nextTick 的原理是什么?
1)為什么需要 nextTickVue 是異步修改 DOM 的并且不鼓勵開發(fā)者直接接觸 DOM,但有時候業(yè)務需要必須對數(shù)據(jù)更改--刷新后的 DOM 做相應的處理,這時候就可以使用 Vue.nextTick(callback)這個 api 了。2)理解原理前的準備首先需要知道事件循環(huán)中宏任務和微任務這兩個概念(這其實也是面試常考點)。常見的宏任務有:?script, setTimeout, setInterval, setImmediate, I/O, UI rendering常見的微任務有:process.nextTick(Nodejs),Promise.then(), MutationObserver;3)理解 nextTick而 nextTick 的原理正是 vue 通過異步隊列控制 DOM 更新和 nextTick 回調函數(shù)先后執(zhí)行的方式。如果大家看過這部分的源碼,會發(fā)現(xiàn)其中做了很多 isNative()的判斷,因為這里還存在兼容性優(yōu)雅降級的問題。可見 Vue 開發(fā)團隊的深思熟慮,對性能的良苦用心Vue3.0 是如何變得更快的?
diff 方法優(yōu)化Vue2.x 中的虛擬 dom 是進行全量的對比。Vue3.0 中新增了靜態(tài)標記(PatchFlag):在與上次虛擬結點進行對 比的時候,值對比帶有 patch flag 的節(jié)點,并且可以通過 flag 的信息 得知當前節(jié)點要對比的具體內容化。hoistStatic 靜態(tài)提升Vue2.x : 無論元素是否參與更新,每次都會重新創(chuàng)建。Vue3.0 : 對不參與更新的元素,只會被創(chuàng)建一次,之后會在每次渲染時 候被不停的復用。cacheHandlers 事件偵聽器緩存 默認情況下 onClick 會被視為動態(tài)綁定,所以每次都會去追蹤它的 變化但是因為是同一個函數(shù),所以沒有追蹤變化,直接緩存起來復用 即可。算法和手寫編程題
算法:鏈表、棧和隊列、二叉樹
性能優(yōu)化
web 性能優(yōu)化?
降低請求量:合并資源,減少 HTTP 請求數(shù),minify / gzip 壓縮, webP,lazyLoad。加快請求速度:預解析 DNS,減少域名數(shù),并 行加載,CDN 分發(fā)。緩存:HTTP 協(xié)議緩存請求,離線緩存 manifest,離線數(shù)據(jù)緩存 localStorage。渲染:JS/CSS 優(yōu)化,加載順序,服務端渲染,pipeline如何提高小程序的首屏加載時間?
提前請求:異步數(shù)據(jù)數(shù)據(jù)請求不需要等待頁面渲染完成利用緩存:利用 storage API 對異步請求數(shù)據(jù)進行緩存,二次啟動時 先利用緩存數(shù)據(jù)渲染頁面,再進行后臺更新避免白屏:先展示頁面骨架和基礎內容 及時反饋:及時地對需要用戶等待的交互操作給出反饋,避免用戶以 為小程序沒有響應性能優(yōu)化:避免不當使用 setdata 和 onpagescrollwebpack相關
webpack 的打包原理
Webpack 是把項目當做一個整體,通過給定一個主文件,webpack 將從這個主文件開始找到項目中所有依賴的文件,使用 loaders 類處 理,最后打包成一個或者多個瀏覽器可識別的 js 文件webpack 中的 loaders 與 plugin 的區(qū)別
什么是 loaders:loaders 是文件加載器,能夠加載資源文件,并對 這些文件進行處理,例如,編譯,壓縮等,最終一起打包到指定文件 中。什么是 plugin:在 webpack 運行的生命周期會有許多事件,plugin 可以監(jiān)聽這些事件 區(qū)別:加載器是用來加載文件的,webpack 本身只能加載 js 文件(內 置 babel-loader),加載其他文件就需要安裝別的 loader,比如: css-loader file-loader Plugin 是擴展 webpack 功能的,通過 plugin ,webpack 可以實 現(xiàn) loader 不能完成的復雜功能Webpack 與 gulp 區(qū)別
Gulp 是一種能夠優(yōu)化前端開發(fā)流程的工具webpack 是一種模塊化的解決方案 (grunt)git高級操作
git?checkout?-??導航?——?跳到之前的分支
查看歷史
#?每個提交在一行內顯示?git?log?--oneline???#?在所有提交日志中搜索包含「homepage」的提交??git?log?--all?--grep='homepage'??#?獲取某人的提交日志??git?log?--author="Maxence"
不想提交,又要回滾
git?reset?--hard?<提交的哈希值>
查看我的分支和?master?的不同
git?diff?master..my-branch
#?在最近?3?個提交上運行?`npm?test`?命令
git?rebase?HEAD~3?--exec?"npm?test"
前端微服務
特點
- 獨立部署
- 獨立開發(fā)
技術無關
不影響用戶體驗
6種方式
路由分發(fā)式微前端通過路由將不同的業(yè)務分發(fā)到不同的、獨立前端應用上。其通??梢酝ㄟ^ HTTP 服務器的反向代理來實現(xiàn),又或者是應用框架自帶的路由來解決。- 網(wǎng)站不需要 SEO 支持
- 需要設置加載機制
需要設置通訊機制
- 獨立構建組件和應用,生成 chunk 文件,構建后再歸類生成的 chunk 文件。(這種方式更類似于微服務,但是成本更高)
- 開發(fā)時獨立開發(fā)組件或應用,集成時合并組件和應用,最后生成單體的應用。
在運行時,加載應用的 Runtime,隨后加載對應的應用代碼和模板。
但是,首先它有一個嚴重的限制:必須使用同一個框架。
其次,采用這種方式還有一個限制,那就是:規(guī)范!**規(guī)范!**規(guī)范!。在采用這種方案時,我們需要:
統(tǒng)一依賴。統(tǒng)一這些依賴的版本,引入新的依賴時都需要一一加入。
規(guī)范應用的組件及路由。避免不同的應用之間,因為這些組件名稱發(fā)生沖突。
構建復雜。在有些方案里,我們需要修改構建系統(tǒng),有些方案里則需要復雜的架構腳本。
共享通用代碼。這顯然是一個要經(jīng)常面對的問題。
制定代碼規(guī)范。
- 重寫現(xiàn)有的前端應用。是的,現(xiàn)在我們需要完成使用 Web Components 來完成整個系統(tǒng)的功能。
- 上下游生態(tài)系統(tǒng)不完善。缺乏相應的一些第三方控件支持,這也是為什么 jQuery 相當流行的原因。需要設置通訊機制
- 系統(tǒng)架構復雜。當應用被拆分為一個又一個的組件時,組件間的通訊就成了一個特別大的麻煩。
- 瀏覽器兼容問題
現(xiàn)有框架(single-spa、qiankun、mooa)其中single-spa已經(jīng)實現(xiàn)了大部分框架(vue、react、angular)的啟動和卸載處理,但不適用于生產環(huán)境qiankun是基于spa-single實現(xiàn)的以運行在生產環(huán)境為目標的微前端服務框架Mooa是一個僅僅基于angular框架的微前端框架
設計模式
簡單工廠- 處理變與不變的工廠模式:將創(chuàng)建對象的過程單獨封裝,實現(xiàn)無腦傳參,核心:處理變與不變的抽象工廠- 開放封閉原則簡單工廠因為沒有遵守開放封閉原則,?暴露一個很大的缺陷。例如若我們添加管理層一些考評權限,難道我們要重新去修改Factory函數(shù)嗎?這樣做會導致Factory會變得異常龐大,而且很容易出bug,最后非常難維護
單例模式 - 保證一個類只有一個實例保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。單例模式要求不管我們嘗試去創(chuàng)建多少次,它都只給你返回第一次所創(chuàng)建的那唯一的一個實例。
裝飾器模式 - 實現(xiàn)只添加不修改適配器模式 - 兼容就是一把梭代理模式事件代理:點擊子元素,用父元素代理緩存代理
觀察者模式
結束
關注前端早茶,一起攜手進階
歡迎關注前端早茶,與廣東靚仔攜手共同進階~
