目錄
HTML
標(biāo)簽語(yǔ)意化
HTML5新特性
SEO
input元素的類型
iframe的特點(diǎn)
CSS
Flex
BFC
重排重繪
CSS優(yōu)先級(jí)
CSS3新特性
清除浮動(dòng)的方法
盒模型的理解
響應(yīng)式布局
移動(dòng)適配方案
三欄布局
圣杯布局和雙飛翼布局
JS
JS為何是單線程
JS數(shù)據(jù)類型
js判斷數(shù)據(jù)類型
js中的length屬性
判斷空對(duì)象
判斷空數(shù)組
ES6新特性
ES6 Module 和 CommonJS 的區(qū)別
箭頭函數(shù)和普通函數(shù)區(qū)別
new一個(gè)對(duì)象做了什么事情
構(gòu)造函數(shù)與普通函數(shù)的區(qū)別
防抖和節(jié)流
深拷貝淺拷貝
數(shù)組去重
原型鏈
call、bind、apply的含義和區(qū)別
Class
Class和構(gòu)造函數(shù)的區(qū)別
js繼承的幾種方式及其優(yōu)缺點(diǎn)
閉包
瀏覽器的緩存機(jī)制
任務(wù)隊(duì)列(宏/微任務(wù))
事件委托
請(qǐng)求
請(qǐng)求的方式有哪些,應(yīng)用場(chǎng)景是什么
什么是promise,解決了什么問(wèn)題
談?wù)剬?duì)async/await的理解
跨越問(wèn)題如何解決
輸入網(wǎng)站url地址后發(fā)生了什么
ajax工作流程及原理
axios 是什么、怎么使用
Localstorage、sessionStorage、cookie 的區(qū)別
后端接口沒(méi)寫出來(lái),前端如何進(jìn)行開發(fā)
post請(qǐng)求和get請(qǐng)求的區(qū)別
Session,Token,Cookie在身份認(rèn)證方面的區(qū)別
常見的狀態(tài)碼
Vue2
Vue是什么
MVVM
觀察者模式和發(fā)布訂閱者模式
SPA(單頁(yè)應(yīng)用)的理解
響應(yīng)式原理
Vue2生命周期
data為什么是函數(shù)的存在
Vue組件通信的方式
keep-alive原理及緩存策略
computed原理
watch原理
computed和methods、watch的區(qū)別
vue-router原理
Vue3
Vue2和Vue3響應(yīng)式原理的區(qū)別
Vue3生命周期
選項(xiàng)式API和組合式API
VueX和Pinia的區(qū)別、優(yōu)劣
Vite好在哪為什么
TS
對(duì)ts的理解
ts的數(shù)據(jù)類型
never和void的區(qū)別
枚舉的理解
泛型
項(xiàng)目
token超時(shí)處理
登錄頁(yè)面安全問(wèn)題
發(fā)布通知功能怎么實(shí)現(xiàn)
項(xiàng)目剛上線出現(xiàn)bug
用什么進(jìn)行版本管理
Echarts在Vue里怎么使用
Echarts里的配置項(xiàng)不夠用怎么辦
團(tuán)隊(duì)中有的人用vue2有的人用vue3怎么辦
項(xiàng)目?jī)?yōu)化
PC端兼容問(wèn)題
img下的留白
如果圖片加a標(biāo)簽在IE9-中會(huì)有邊框
移動(dòng)端問(wèn)題
移動(dòng)端頁(yè)面滾動(dòng)滯澀感
修改移動(dòng)端的點(diǎn)擊高亮效果
滾動(dòng)穿透問(wèn)題
在ios和andriod中,audio元素和video元素在無(wú)法自動(dòng)播放
iOS 系統(tǒng)中文輸入法輸入英文時(shí),字母之間可能會(huì)出現(xiàn)一個(gè)六分之一空格
IOS移動(dòng)端click事件300ms的延遲響應(yīng)
阻止旋轉(zhuǎn)屏幕時(shí)自動(dòng)調(diào)整字體大小
圖片模糊問(wèn)題
移動(dòng)端某些情況下input的placeholder會(huì)出現(xiàn)文本位置偏上的現(xiàn)象
h5底部輸入框被鍵盤遮擋問(wèn)題
移動(dòng)端如何做真機(jī)測(cè)試
H5和app的區(qū)別
HTML
標(biāo)簽語(yǔ)意化
簡(jiǎn)單來(lái)說(shuō):就是用正確的標(biāo)簽做正確的事。比如:
-
頭部:header
-
導(dǎo)航:nav
-
主體內(nèi)容:main
-
標(biāo)題:h1 ~ h6
-
段落:p
-
側(cè)邊欄:aside
-
頁(yè)腳:footer
這樣,整篇HTML結(jié)構(gòu)非常清晰,好看。
HTML語(yǔ)義化有什么好處呢?
-
網(wǎng)頁(yè)加載慢導(dǎo)致CSS文件還未加載時(shí)(沒(méi)有CSS),頁(yè)面仍然清晰、可讀、好看。
-
提升用戶體驗(yàn),例如title、alt可用于解釋名詞或解釋圖片信息。
-
有利于SEO:和搜索引擎建立良好溝通,有助于爬蟲抓取更多的有效信息。
-
方便其他設(shè)備(如屏幕閱讀器、盲人閱讀器、移動(dòng)設(shè)備)更好的解析頁(yè)面。
-
使代碼更具可讀性,便于團(tuán)隊(duì)開發(fā)和維護(hù)。
HTML5新特性
-
更加語(yǔ)義化的元素。 article、footer、header、nav、section
-
本地化儲(chǔ)存。 localStorage 和 sessionStorage
-
拖曳以及釋放的api。 Drag and drop(draggable="true";當(dāng)拖拽一個(gè)項(xiàng)目到 HTML 元素中時(shí),瀏覽器默認(rèn)不會(huì)有任何響應(yīng)。想要讓一個(gè)元素變成可釋放區(qū)域,該元素必須設(shè)置 ondragover和 ondrop 事件。)
-
媒體播放。 video 和 audio
-
增強(qiáng)表單控件類型。date、time、number、email、color、search
-
全雙工通信協(xié)議。 websocket
-
跨域資源共享(CORS) Access-Control-Allow-Origin
補(bǔ)充:Web Storage 的概念和 cookie 相似,區(qū)別是它是為了更大容量存儲(chǔ)設(shè)計(jì)的。Cookie 的大小是受限的,并且每次你請(qǐng)求一個(gè)新的頁(yè)面的時(shí)候 Cookie 都會(huì)被發(fā)送過(guò)去,這樣無(wú)形中浪費(fèi)了帶寬,另外 cookie 還需要指定作用域,不可以跨域調(diào)用。
1.localStorage: 用于持久化的本地存儲(chǔ),除非主動(dòng)刪除數(shù)據(jù),否則數(shù)據(jù)是永遠(yuǎn)不會(huì)過(guò)期的。
2.sessionStorage: 用于本地存儲(chǔ)一個(gè)會(huì)話(session)中的數(shù)據(jù),這些數(shù)據(jù)只有在同一個(gè)會(huì)話中的頁(yè)面才能訪問(wèn)并且當(dāng)會(huì)話結(jié)束后數(shù)據(jù)也隨之銷毀。因此 sessionStorage 不是一種持久化的本地存儲(chǔ),僅僅是會(huì)話級(jí)別的存儲(chǔ)。
Web Storage 擁有 setItem,getItem,removeItem,clear 等方法,不像 cookie 需要前端開發(fā)者自己封裝 setCookie,getCookie(安裝依賴js-cookie、Cookies.set()、Cookies.get()、Cookies.remove)
SEO
SEO(Search Engine Optimization),即搜索引擎優(yōu)化。SEO的存在就是為了提升網(wǎng)站在搜索引擎中的權(quán)重,增加對(duì)搜索引擎的友好度,使得用戶在訪問(wèn)網(wǎng)站時(shí)能排在前面。
-
突出重要內(nèi)容---合理的設(shè)計(jì)
title
、description
和keywords
-
語(yǔ)義化書寫HTML代碼,符合W3C標(biāo)準(zhǔn)
-
圖片
img
標(biāo)簽添加alt
和title
屬性 -
鏈接
<a>
頁(yè)內(nèi)標(biāo)簽添加title
屬性 -
使用h1標(biāo)簽自帶權(quán)重
input元素的類型
① button ② checkbox ③ file ④ hidden ⑤ image ⑥ password ⑦ radio ⑧ reset ⑨ submit ⑩ Text ? Date
iframe的特點(diǎn)
-
優(yōu)點(diǎn):
-
iframe能夠原封不動(dòng)的把嵌入的網(wǎng)頁(yè)展現(xiàn)出來(lái)。
-
如果有多個(gè)網(wǎng)頁(yè)引用iframe,那么你只需要修改iframe的內(nèi)容,就可以實(shí)現(xiàn)調(diào)用的每一個(gè)頁(yè)面內(nèi)容的更改,方便快捷。
-
網(wǎng)頁(yè)如果為了統(tǒng)一風(fēng)格,頭部和版本都是一樣的,就可以寫成一個(gè)頁(yè)面,用iframe來(lái)嵌套,可以增加代碼的可重用。
-
如果遇到加載緩慢的第三方內(nèi)容如圖標(biāo)和廣告,這些問(wèn)題可以由iframe來(lái)解決。
-
缺點(diǎn):
-
iframe會(huì)阻塞主頁(yè)面的onload事件;
-
iframe和主頁(yè)面共享連接池,而瀏覽器對(duì)相同域的連接有限制,所以會(huì)影響頁(yè)面的并行加載。,會(huì)產(chǎn)生很多頁(yè)面,不容易管理。
-
iframe框架結(jié)構(gòu)有時(shí)會(huì)讓人感到迷惑,如果框架個(gè)數(shù)多的話,可能會(huì)出現(xiàn)上下、左右滾動(dòng)條,會(huì)分散訪問(wèn)者的注意力,用戶體驗(yàn)度差。
-
代碼復(fù)雜,無(wú)法被一些搜索引擎索引到,這一點(diǎn)很關(guān)鍵,現(xiàn)在的搜索引擎爬蟲還不能很好的處理iframe中的內(nèi)容,所以使用iframe會(huì)不利于搜索引擎優(yōu)化(SEO)。
-
很多的移動(dòng)設(shè)備無(wú)法完全顯示框架,設(shè)備兼容性差。
-
iframe框架頁(yè)面會(huì)增加服務(wù)器的http請(qǐng)求,對(duì)于大型網(wǎng)站是不可取的。
CSS
Flex
-
哪些屬性作用在父元素上?
justify-content:space-around space-between space-evently center flex-end
align-items:flex-star flex-end
flex-direction :row row-reverse column column-reverse
flex-wrap :nowrap(如果子孩子,的寬度超過(guò)父盒子,會(huì)進(jìn)行總動(dòng)的伸縮) wrap(不去管)
-
哪些屬性作用在子元素上?
order (項(xiàng)目排列的順序 越小越靠前)
align-self(單個(gè)屬性的操作 flex-end center flex-star)
flex-grow(如果剩余有寬度是否進(jìn)行擴(kuò)張方法,默認(rèn)是0,)
flex-shrink (空間不足的時(shí)候進(jìn)行縮小默認(rèn)是1 進(jìn)行縮?。?/p>
BFC
定義:
塊級(jí)格式化上下文。BFC
是一個(gè)完全獨(dú)立的空間(布局環(huán)境),讓空間里的子元素不會(huì)影響到外面的布局。用于對(duì)塊級(jí)元素排版。默認(rèn)情況下只有根元素(body)一個(gè)塊級(jí)上下文。
布局規(guī)則:
-
內(nèi)部的盒子會(huì)在垂直方向,一個(gè)個(gè)地放置;
-
盒子垂直方向的距離由
margin
決定,屬于同一個(gè)BFC
的兩個(gè)相鄰盒子的上下margin
會(huì)發(fā)生重疊; -
每一個(gè)元素的左邊,與包含塊的左邊相接觸(對(duì)于從右往左的布局,則相反),即使存在浮動(dòng)也是如此;
-
BFC
的區(qū)域不會(huì)與float
重疊;(應(yīng)用:三欄布局) -
BFC
就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器,容器里面的子元素不會(huì)影響到外面的元素。反之也如此; -
計(jì)算
BFC
的高度時(shí),浮動(dòng)元素也參與計(jì)算。(運(yùn)用:清除浮動(dòng)) -
當(dāng)一個(gè)元素設(shè)置了新的
BFC
后,就和這個(gè)元素外部的BFC
沒(méi)有關(guān)系了,這個(gè)元素只會(huì)去約束自己內(nèi)部的子元素。(應(yīng)用:外邊距塌陷)
怎么觸發(fā)BFC:
-
overflow:不為
visible
; -
float: 不為
none
; -
display: 為
inline-block
、table
、table-cell
、table-caption
、flex
、inline-flex
、grid
、inline-grid
、flow-root
; -
position: 為
absolute
或者fixed
;
重排重繪
頁(yè)面生成的過(guò)程:
1.HTML 被 HTML 解析器解析成 DOM 樹;
2.CSS 被 CSS 解析器解析成 CSSOM 樹;
3.結(jié)合 DOM 樹和 CSSOM 樹,生成一棵渲染樹(Render Tree),這一過(guò)程稱為 Attachment;
4.生成布局(flow),瀏覽器在屏幕上“畫”出渲染樹中的所有節(jié)點(diǎn);
5.將布局繪制(paint)在屏幕上,顯示出整個(gè)頁(yè)面。
第四步和第五步是最耗時(shí)的部分,這兩步合起來(lái),就是我們通常所說(shuō)的渲染。
-
重繪:某些元素的外觀被改變,例如:元素的填充顏色
-
重排:重新生成布局,重新排列元素。
單單改變?cè)氐耐庥^,肯定不會(huì)引起網(wǎng)頁(yè)重新生成布局,但當(dāng)瀏覽器完成重排之后,將會(huì)重新繪制受到此次重排影響的部分。比如改變?cè)馗叨?,這個(gè)元素乃至周邊dom都需要重新繪制。
也就是說(shuō):重繪不一定導(dǎo)致重排,但重排一定會(huì)導(dǎo)致重繪。
CSS優(yōu)先級(jí)
!important > style > id > class > 標(biāo)簽 > 通配符 > 默認(rèn) > 繼承
CSS3新特性
-
新增的選擇器(各種偽類選擇器)
-
圓角(border-radius)
-
陰影(box-shadow)
-
動(dòng)畫(animation)
-
過(guò)渡(transition)
-
翻轉(zhuǎn)(transform)
-
漸變
-
媒體查詢 @media
-
彈性盒子(flex)
-
rgba
清除浮動(dòng)的方法
為什么要清除浮動(dòng)?
如果子元素浮動(dòng),此時(shí)子元素不能撐開標(biāo)準(zhǔn)流的塊級(jí)父元素。
方法:
1、直接給父元素設(shè)置高度
-
優(yōu)點(diǎn):簡(jiǎn)單、方便
-
缺點(diǎn):有很多布局不能固定父元素高度:比如長(zhǎng)列表、推薦模塊,是無(wú)法確定子項(xiàng)內(nèi)容有多少的
2、額外標(biāo)簽法
-
實(shí)現(xiàn)方式:
-
給父元素內(nèi)容的最后添加一個(gè)塊級(jí)元素
-
給添加的塊級(jí)元素設(shè)置
clear: both;
(可以認(rèn)為,設(shè)置了clear:both
的當(dāng)前元素會(huì)把前邊元素中設(shè)有浮動(dòng)屬性的元素,當(dāng)做沒(méi)設(shè)浮動(dòng)一樣來(lái)看待,以此來(lái)消除其對(duì)自己的影響)
-
-
缺點(diǎn):
-
會(huì)添加進(jìn)去額外的標(biāo)簽,讓HTML結(jié)構(gòu)變得復(fù)雜
-
3、單偽元素清除法
用偽元素替代額外標(biāo)簽
4、雙偽元素清除法
除了可以清除浮動(dòng)的影響,還可以解決外邊距折疊的塌陷現(xiàn)象(原理:里面的"display:table;"觸發(fā)BFC)
5、為父元素設(shè)置overflow: hidden
盒模型的理解
分標(biāo)準(zhǔn)盒模型和怪異盒模型。
標(biāo)準(zhǔn)盒模型采用的W3C標(biāo)準(zhǔn),盒子的content內(nèi)容部分由width寬度和height高度決定,添加padding內(nèi)邊距或border外邊框后,寬高都會(huì)進(jìn)行相應(yīng)增長(zhǎng)。
怪異盒模型也稱為IE盒模型,是IE瀏覽器設(shè)計(jì)元素時(shí)遵循的規(guī)則。怪異盒模型的寬高在div盒子初次設(shè)置時(shí)就已經(jīng)規(guī)定,添加padding或者border,會(huì)從中減少content內(nèi)容的占據(jù)區(qū)域,來(lái)為padding和border制造空間,寬高不會(huì)相對(duì)應(yīng)的進(jìn)行增長(zhǎng)。
盒模型轉(zhuǎn)換用box-sizing:border-box,默認(rèn)是標(biāo)準(zhǔn)盒模型。
響應(yīng)式布局
-
bootstrop框架
-
媒體查詢
移動(dòng)適配方案
-
rem(用
flexible
方案,flexible.js幫我們計(jì)算出1rem 等于多少px) -
vw和vh
三欄布局
-
flex
-
定位
-
浮動(dòng)
-
-
兩邊浮動(dòng)中間margin + overflow: hidden(觸發(fā)BFC)
-
兩邊浮動(dòng),中間calc()函數(shù)
-
三個(gè)部分都浮動(dòng)(圣杯和雙飛翼布局),然后結(jié)合margin和定位調(diào)整
-
-
display:table;
-
grid布局
圣杯布局和雙飛翼布局
最后我們來(lái)總結(jié)一下,雙飛翼布局其實(shí)和圣杯布局的精髓是一樣的,都是在三個(gè)部分都是浮動(dòng)的情況下,左右的部分因?yàn)楦负凶訉挾炔粔虮粩D下來(lái)的問(wèn)題,通過(guò)設(shè)置負(fù)margin來(lái)實(shí)現(xiàn)元素的排布。
-
不同的就是html結(jié)構(gòu),雙飛翼是在middle元素內(nèi)部又設(shè)置了一個(gè)milddle-inner并設(shè)置它的左右margin,而非圣杯布局的padding,來(lái)排除兩邊元素的覆蓋,最后把盒子定位到兩側(cè)。
-
雙飛翼布局可以多了一個(gè)html結(jié)構(gòu),但是可以不用設(shè)置left,right元素的定位。
JS
JS為何是單線程
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語(yǔ)言,JavaScript的主要用途是與用戶互動(dòng),以及操作DOM。這決定了它只能是單線程,否則會(huì)帶來(lái)很復(fù)雜的同步問(wèn)題。比如,假定JavaScript同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)?
所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成這門語(yǔ)言的核心特征,將來(lái)也不會(huì)改變。
注:所謂單線程,是指在JS引擎中負(fù)責(zé)解釋和執(zhí)行JavaScript代碼的線程只有一個(gè)。
JS數(shù)據(jù)類型
基本類型分為以下六種:
-
string(字符串)
-
boolean(布爾值)
-
number(數(shù)字)
-
symbol(符號(hào))
-
null(空值)
-
undefined(未定義)
-
BigInt(是ES6中新引入的數(shù)據(jù)類型,它是一種內(nèi)置對(duì)象,它提供了一種方法來(lái)表示表示任意大的整數(shù)。即使這個(gè)數(shù)已經(jīng)超出了JavaScript構(gòu)造函數(shù) Number 能夠表示的安全整數(shù)范圍。)
引用數(shù)據(jù)類型:
-
數(shù)組
-
對(duì)象(函數(shù)也是對(duì)象)
區(qū)別:
值類型的變量會(huì)保存在 棧內(nèi)存 中,如果在一個(gè)函數(shù)中聲明一個(gè)值類型的變量,那么這個(gè)變量當(dāng)函數(shù)執(zhí)行結(jié)束之后會(huì) 自動(dòng)銷毀。
引用類型的變量名會(huì)保存在 棧內(nèi)存 中,但是變量值會(huì)存儲(chǔ)在 堆內(nèi)存 中,引用類型的變量不會(huì)自動(dòng)銷毀,當(dāng)沒(méi)有引用變量引用它時(shí),系統(tǒng)的 垃圾回收機(jī)制 會(huì)回收它。
js判斷數(shù)據(jù)類型
判斷數(shù)據(jù)類型方法有很多,實(shí)際使用需要根據(jù)自己的需求使用最適合自己的方法
1、使用 typeof
測(cè)試簡(jiǎn)單數(shù)據(jù)類型。對(duì)于
null
及數(shù)組、對(duì)象,typeof均檢測(cè)出為object,不能進(jìn)一步判斷它們的類型。
2、使用 obj instanceof Object
測(cè)試復(fù)雜數(shù)據(jù)類型,因?yàn)閕nstanceof 是用來(lái)判斷數(shù)據(jù)是否是某個(gè)對(duì)象的實(shí)例
所以對(duì)于
null
和undefined
這兩個(gè)家伙就檢測(cè)不了因?yàn)樵玩溊^承的關(guān)系,instanceof 會(huì)把數(shù)組都識(shí)別為 Object 對(duì)象,所有引用類型的祖先都是 Object 對(duì)象
3、使用Object.prototype.toString.call
Object.prototype.toString.call() 區(qū)分的數(shù)據(jù)類型適用范圍更大,但是無(wú)法區(qū)分自定義對(duì)象類型,區(qū)分自定義對(duì)象類型使用 instanceof 操作符。
Object.prototype.toString()本身是允許被修改的,而我們目前所討論的關(guān)于Object.prototype.toString()這個(gè)方法的應(yīng)用都是假設(shè)toString()方法未被修改為前提的。
因?yàn)閷?shí)例對(duì)象有可能會(huì)自定義toString()方法,會(huì)覆蓋Object.prototype.toString(), 所以在使用時(shí),最好加上call()。
4、使用.constructor
constructor不能判斷undefined和null,并且使用它是不安全的,因?yàn)閏ontructor的指向是可以改變的
js中的length屬性
1、length屬性常見于字符串和數(shù)組,來(lái)判斷長(zhǎng)度。
2、length屬性還可以用于函數(shù),來(lái)判斷函數(shù)的長(zhǎng)度,即函數(shù)中形參的個(gè)數(shù)。
注意:
-
...args
不計(jì)入形參個(gè)數(shù) -
設(shè)置了默認(rèn)值的參數(shù)及其之后的所有參數(shù)都不計(jì)入形參個(gè)數(shù),之前的仍舊計(jì)入
判斷空對(duì)象
所謂空對(duì)象,就是數(shù)組的長(zhǎng)度等于0
let obj = {name : '你好'}
//是true為空對(duì)象,是false則不是空對(duì)象
console.log(JSON.stringify(obj) === '{}');//false
let obj = {}
?
let fn = (obj) => {
? ?for(let key in obj) {
? ? ? ?return false
? }
?
? ?return true
}
//返回false代表不為空,返回true則為空對(duì)象
console.log(fn(obj));//true
let ?obj = {name : '1'}
?
//Object.getOwnPropertyNames()獲取到對(duì)象中的全部屬性名,存到一個(gè)數(shù)組中
let s = Object.getOwnPropertyNames(obj)
console.log(s); //['name'] ? //為[],代表空對(duì)象
let ?obj = {name : '1'}
//Object.keys()獲取給定對(duì)象的所有可枚舉屬性的字符串?dāng)?shù)組
let s = Object.keys(obj)
console.log(s);//[ 'name' ] //若為[],則為空對(duì)象
let ?obj = {name : '1'}
// 注意for...in 會(huì)將對(duì)象原型鏈上的屬性也枚舉出來(lái),所以要借hasOwnProperty()方法來(lái)判斷是不是對(duì)象本身的屬性
// 如果存在返回true,不存在返回false
let fn = (s) => {
? ?for(let key in s) {
? ? ? ?if(s.hasOwnProperty(key)) {
? ? ? ? ? ?return false
? ? ? }
? ? ? ?return true
? }
}
console.log(fn(obj));//false ? //若是反回true則就是空對(duì)象
判斷空數(shù)組
和判斷空對(duì)象類似的,我們只要能驗(yàn)證這個(gè)對(duì)象的keys
長(zhǎng)度是0,那就是個(gè)空對(duì)象了。
Array.isArray(arr) & arr.length === 0
ES6新特性
-
新的定義變量的方式 let const var 的區(qū)別
-
模板字符串
-
class
-
Promise
-
async/await
-
箭頭函數(shù)
-
新的數(shù)組方法 filter some map every forEach reduce Array.from() find findIndex includes flat
-
拓展運(yùn)算符
-
賦值解構(gòu)運(yùn)算符
-
Proxy
-
對(duì)象新增方法 Object.assign() Object.keys()
-
es6的模塊化
-
Set
-
Map
ES6 Module 和 CommonJS 的區(qū)別
CommonJS 是對(duì)模塊的淺拷貝;ES6 Module 是對(duì)模塊的引用,即 ES6。
CommonJS是動(dòng)態(tài)編譯,可以放在代碼里動(dòng)態(tài)執(zhí)行;ES6 Module 是靜態(tài)編譯,引用只能放在最前面。
箭頭函數(shù)和普通函數(shù)區(qū)別
-
this指向(普通函數(shù)指向調(diào)用者,this指向父級(jí)作用域的this)
-
不可以被當(dāng)做構(gòu)造函數(shù)
-
不可以使用arguments對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在,如果要用就用剩余參數(shù)替代
-
沒(méi)有prototype屬性
new一個(gè)對(duì)象做了什么事情
-
new構(gòu)建函數(shù)可以在內(nèi)存中創(chuàng)建一個(gè)空的對(duì)象
-
this會(huì)指向剛才創(chuàng)建的空對(duì)象
-
執(zhí)行構(gòu)造函數(shù)的代碼給這個(gè)空對(duì)象添加屬性和方法
-
返回這個(gè)對(duì)象(所以構(gòu)造函數(shù)不需要return)
構(gòu)造函數(shù)與普通函數(shù)的區(qū)別
1.構(gòu)造函數(shù)就是一個(gè)普通的函數(shù),創(chuàng)建方法和普通函數(shù)沒(méi)有區(qū), 不同的是構(gòu)造函數(shù)習(xí)慣上首字母大寫。
2.構(gòu)造函數(shù)與普通函數(shù)的區(qū)別就是調(diào)用方式不同,普通函數(shù)直接調(diào)用,而構(gòu)造函數(shù)使用new關(guān)鍵字調(diào)用。
防抖和節(jié)流
-
防抖debounce
定義:觸發(fā)高頻事件后n秒內(nèi)函數(shù)只會(huì)執(zhí)行最后一次,如果n秒內(nèi)高頻事件再次被觸發(fā),則重新計(jì)算時(shí)間。
原理:每次觸發(fā)事件時(shí)都取消之前的延時(shí)調(diào)用方法
function debounce(fn) { ?let timer = null; // 創(chuàng)建一個(gè)標(biāo)記用來(lái)存放定時(shí)器的返回值 ?return function () { ? ?// 執(zhí)行這個(gè)函數(shù)之前先清掉定時(shí)器 ? ?clearTimeout(timer); ? ?timer = setTimeout(() => { ? ? ?// 綁定this的原因是為了讓this指向正確 ? ? ?// 綁定arguments的原因是為了正確使用函數(shù)參數(shù)位置的事件對(duì)象e ? ? ?fn.apply(this, arguments); ? }, 500); }; }
應(yīng)用場(chǎng)景:
-
搜索框輸入查詢,如果用戶一直在輸入中,沒(méi)有必要不停地調(diào)用去請(qǐng)求服務(wù)端接口,等用戶停止輸入的時(shí)候,再調(diào)用,設(shè)置一個(gè)合適的時(shí)間間隔,有效減輕服務(wù)端壓力。
-
表單驗(yàn)證
-
按鈕提交事件。
-
瀏覽器窗口縮放,resize事件(如窗口停止改變大小之后重新計(jì)算布局)等
-
-
節(jié)流throttle
定義:高頻事件觸發(fā),但在n秒內(nèi)只會(huì)執(zhí)行一次,所以節(jié)流會(huì)稀釋函數(shù)的執(zhí)行頻率
原理:每次觸發(fā)事件時(shí)都判斷當(dāng)前是否有等待執(zhí)行的延時(shí)函數(shù)
方法一: function throttle(func, wait) { ? ?var prev = 0; ? ?return function() { ? ? ? ?let now = Date.now(); ? ? ? ?if (now - prev > wait) { ? ? ? ? ? ?func(); ? ? ? ? ? ?// 重置起始時(shí)間 ? ? ? ? ? ?prev = now; ? ? ? } ? } } 方法二: function throttle(fn) { ?// 閉包保存是否可以開啟定時(shí)器,默認(rèn)是開啟的 ?let canRun = true; ?return function () { ? ?// 如果沒(méi)有開啟就直接返回 ? ?if (!canRun) return; ? ?// 開啟了就立即關(guān)閉定時(shí)器入口,然后開啟定時(shí)器 ? ?canRun = false; ? ?setTimeout(() => { ? ? ?fn.apply(this, arguments); ? ? ?// 定時(shí)器運(yùn)行后,下次定時(shí)器才可開啟 ? ? ?canRun = true; ? }, 500); }; }
應(yīng)用場(chǎng)景:
-
按鈕點(diǎn)擊事件
-
拖拽事件
-
onScoll
-
計(jì)算鼠標(biāo)移動(dòng)的距離(mousemove)
-
深拷貝淺拷貝
-
淺拷貝
-
展開運(yùn)算符...
const array = [{ type: '??' }, '??', '??'] const copyArray = [...array] ? array[0].type = '??' // 修改原數(shù)組 console.log(array, copyArray) // 原數(shù)組和復(fù)制的數(shù)組都變成了[{ type: '??' }, '??', '??']
-
Object.assign()
const array = [{ type: '??' }, '??', '??'] const copyArray = Object.assign([], array) ? array[0].type = '??' // 修改原數(shù)組 console.log(array, copyArray) // 原數(shù)組和復(fù)制的數(shù)組都變成了[{ type: '??' }, '??', '??']
-
Array.prototype.concat()
const array = [{ type: '??' }, '??', '??'] const copyArray = array.concat([]) ? array[0].type = '??' // 修改原數(shù)組 console.log(array, copyArray) // 原數(shù)組和復(fù)制的數(shù)組都變成了[{ type: '??' }, '??', '??']
-
Array.prototype.slice()
const array = [{ type: '??' }, '??', '??'] const copyArray = array.slice() ? array[0].type = '??' // 修改原數(shù)組 console.log(array, copyArray) // 原數(shù)組和復(fù)制的數(shù)組都變成了[{ type: '??' }, '??', '??']
-
Array.from()
const array = [{ type: '??' }, '??', '??'] const copyArray = Array.from(array) ? array[0].type = '??' // 修改原數(shù)組 console.log(array, copyArray) // 原數(shù)組和復(fù)制的數(shù)組都變成了[{ type: '??' }, '??', '??']
-
-
深拷貝
1、JSON.parse(JSON.stringify(obj))
-
會(huì)忽略u(píng)ndefined Symbol
-
不能序列化函數(shù)
-
不能解決循環(huán)引用的對(duì)象
-
不能正確處理 new Date()
-
不能處理正則
2、淺拷貝+遞歸
module.exports = function clone(target) { ? ?if (typeof target === 'object') { ? ? ? ?let cloneTarget = Array.isArray(target) ? [] : {}; ? ? ? ?for (const key in target) { ? ? ? ? ? ?cloneTarget[key] = clone(target[key]); ? ? ? } ? ? ? ?return cloneTarget; ? } else { ? ? ? ?return target; ? } };
-
數(shù)組去重
對(duì)于 JS 數(shù)組去重來(lái)說(shuō),其實(shí)萬(wàn)變不離其中,我簡(jiǎn)單的總結(jié)了以下 4 種去重類型
1、數(shù)組元素比較型:
該方法是將數(shù)組的值取出與其他值比較并修改數(shù)組
-
雙層 for 循環(huán)
取出一個(gè)元素,將其與其后所有元素比較,若在其后發(fā)現(xiàn)相等元素,則將后者刪掉
function uniq(arr) {
? ?for (let i = 0; i < arr.length; i++) {
? ? ? ?for (let j = i + 1; j < arr.length; j++) {
? ? ? ? ? ?if (arr[i] === arr[j]) {
? ? ? ? ? ? ? ?arr.splice(j, 1);
? ? ? ? ? ? ? ?j--;
? ? ? ? ? }
? ? ? }
? }
? ?return arr;
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null, NaN, NaN]
// 與 lodash 結(jié)果相比 NaN 沒(méi)有去掉
復(fù)制代碼
由于 NaN === NaN 等于 false,所以重復(fù)的 NaN 并沒(méi)有被去掉
-
排序并進(jìn)行相鄰比較
先對(duì)數(shù)組內(nèi)元素進(jìn)行排序,再對(duì)數(shù)組內(nèi)相鄰的元素兩兩之間進(jìn)行比較,經(jīng)測(cè)試,該方法受限于 sort
的排序能力,所以若數(shù)組不存在比較復(fù)雜的對(duì)象(復(fù)雜對(duì)象難以排序),則可嘗試此方法
function uniq(arr) {
? ?arr.sort();
? ?for (let i = 0; i < arr.length - 1; i++) {
? ? ? ?arr[i] === arr[i + 1] && arr.splice(i + 1, 1) && i--;
? }
? ?return arr;
}
// 運(yùn)行結(jié)果
//[[], [], 1, "1", [1], NaN, NaN, {}, {}, { a: 1 }, {}, { a: 1 }, "a", null, undefined];
// 與 lodash 結(jié)果相比 NaN 沒(méi)有去掉,且對(duì)象的去重出現(xiàn)問(wèn)題
同樣由于 NaN === NaN
等于 false
,所以重復(fù)的 NaN 并沒(méi)有被去掉,并且由于 sort
沒(méi)有將對(duì)象很好的排序,在對(duì)象部分,會(huì)出現(xiàn)一些去重失效
2、查找數(shù)組元素位置型:
該類型即針對(duì)每個(gè)數(shù)組元素進(jìn)行一次查找其在數(shù)組內(nèi)的第一次出現(xiàn)的位置,若第一次出現(xiàn)的位置等于該元素此時(shí)的索引,即收集此元素
-
indexOf
以 indexOf
來(lái)查找元素在數(shù)組內(nèi)第一次出現(xiàn)的位置,若位置等于當(dāng)前元素的位置,則收集
function uniq(arr) {
? ?let res = [];
? ?for (let i = 0; i < arr.length; i++) {
? ? ? ?if (arr.indexOf(arr[i]) === i) {
? ? ? ? ? ?res.push(arr[i]);
? ? ? }
? }
? ?return res;
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null];
// 與 lodash 結(jié)果相比 少了 NaN
indexOf
采用與 ===
相同的值相等判斷規(guī)則,所以在數(shù)組內(nèi)沒(méi)有元素與 NaN 相等,包括它自己,所以 NaN 一個(gè)都不會(huì)被留下
-
findIndex
以 findIndex
方法來(lái)查找元素在數(shù)組內(nèi)第一次出現(xiàn)的位置
function uniq(arr) {
? ?let res = [];
? ?for (let i = 0; i < arr.length; i++) {
? ? ? ?if (arr.findIndex(item => item === arr[i]) === i) {
? ? ? ? ? ?res.push(arr[i]);
? ? ? }
? }
? ?return res;
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null];
// 與 lodash 結(jié)果相比 少了 NaN
結(jié)果原理和 indexOf
相同,因?yàn)橛昧?===
的規(guī)則來(lái)判斷元素是否相等,但此方法相當(dāng)于雙層 for
循環(huán)
3、查找元素是否存在型:
該方法基本依托 includes
方法來(lái)判斷對(duì)應(yīng)元素是否在新數(shù)組內(nèi)存在,若不存在則收集
function uniq(arr) {
? ?let res = [];
? ?for (let i = 0; i < arr.length; i++) {
? ? ? ?if (!res.includes(arr[i])) {
? ? ? ? ? ?res.push(arr[i]);
? ? ? }
? }
? ?return res;
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null, NaN];
// 與 lodash 結(jié)果相同
includes
方法采用 SameValueZero 判斷規(guī)則,所以可以判斷出并去重 NaN
4、依托數(shù)據(jù)類型特性型:
該方案依托于數(shù)據(jù)類型的不重復(fù)特性,以達(dá)到去重效果
-
Map
Map 類型的數(shù)據(jù)可以像 Object 一樣,在設(shè)定元素鍵值對(duì)的時(shí)候可以保證鍵的唯一,并且將鍵的類型拓展到了基本所有元素,包括對(duì)象,在設(shè)定好一個(gè)唯一鍵的 Map 數(shù)據(jù)類型后,再用其自帶的 Map.prototype.keys()
方法取到相應(yīng)的鍵類數(shù)組,最后將類數(shù)組進(jìn)行一次轉(zhuǎn)化即可
function uniq(arr) {
? ?let map = new Map();
? ?for (let i = 0; i < arr.length; i++) {
? ? ? ?!map.has(arr[i]) && map.set(arr[i], true);
? }
? ?return [...map.keys()];
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null, NaN];
// 與 lodash 結(jié)果相同
-
Set
與 Map 類似,但是它里面每一項(xiàng)的值是唯一的,沒(méi)有重復(fù)的值,Set是一個(gè)構(gòu)造函數(shù),用來(lái)生成set的數(shù)據(jù)結(jié)構(gòu)。運(yùn)用數(shù)據(jù)類型的特性完成去重,這個(gè)方法也是最熱門的方法。
function uniq(arr) {
? ?return [...new Set(arr)];
}
// 運(yùn)行結(jié)果
// [1, "1", "a", {}, {}, { a: 1 }, {}, { a: 1 }, [], [], [1], undefined, null, NaN];
// 與 lodash 結(jié)果相同
原型鏈
基于原型對(duì)象的繼承使得不同構(gòu)造函數(shù)的原型對(duì)象關(guān)聯(lián)在一起,并且這種關(guān)聯(lián)的關(guān)系是一種鏈狀的結(jié)構(gòu),我們將原型對(duì)象的鏈狀結(jié)構(gòu)關(guān)系稱為原型鏈。
簡(jiǎn)單地說(shuō):原型鏈就是查找規(guī)則,__proto__對(duì)象原型的意義就在于為對(duì)象成員查找機(jī)制提供一個(gè)方向,或者說(shuō)一條路線。
call、bind、apply的含義和區(qū)別
-
區(qū)別 : 傳參不一樣
call()
-
改變this指向
-
可以調(diào)用函數(shù)
-
參數(shù): 接受的是若干個(gè)參數(shù)的列表 call(this,1,2,3)
apply()
-
改變this指向
-
可以調(diào)用函數(shù)
-
參數(shù): 參數(shù)的數(shù)組 apply(this,[1,2,3])
bind()
-
只改變this指向,不調(diào)用函數(shù),比如用來(lái)改變定時(shí)器內(nèi)部的this指向
Class
-
class本質(zhì)還是function
-
類的所有方法都定義在類的 prototype屬性上
-
類創(chuàng)建的實(shí)例 里面也有 __ proto __ 指向類的 prototype 原型對(duì)象
-
所以 ES6 的類 他的絕大部分功能 es5 都可以做到 新的 calss 寫法 只是讓對(duì)象原型的寫法 更加清晰 更像面向?qū)ο缶幊痰恼Z(yǔ)法而已
-
所以 ES6 的類 其實(shí)就是語(yǔ)法糖
Class和構(gòu)造函數(shù)的區(qū)別
-
類的內(nèi)部所有定義的方法,都是不可枚舉的(但是在es5中prototype的方法是可以進(jìn)行枚舉的)
-
類的構(gòu)造函數(shù),不使用new是沒(méi)法調(diào)用的,會(huì)報(bào)錯(cuò)。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者可以直接調(diào)用
-
Class不存在變量提升(hoist),這一點(diǎn)與ES5完全不同
-
ES5的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象this,然后再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。
js繼承的幾種方式及其優(yōu)缺點(diǎn)
原型鏈繼承
function Parent() {
?this.name = 'kevin';
}
?
Parent.prototype.getName = function () {
?console.log(this.name);
}
?
function Child() {
?
}
?
Child.prototype = new Parent();
Child.prototype.constructor = Child;
?
var child1 = new Child();
console.log(child1.getName()) // kevin
缺點(diǎn):
-
在創(chuàng)建 Child 的實(shí)例時(shí),不能向Parent傳參
-
引用類型的屬性被所有實(shí)例共享
借用構(gòu)造函數(shù)繼承
function Parent() {
?this.names = ['kevin', 'daisy'];
}
?
function Child() {
?Parent.call(this);
}
?
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
?
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]
優(yōu)點(diǎn):
-
可以在 Child 中向 Parent 傳參
-
避免了引用類型的屬性被所有實(shí)例共享
缺點(diǎn):
-
只能繼承父類的實(shí)例屬性和方法,不能繼承原型屬性/方法
-
無(wú)法實(shí)現(xiàn)復(fù)用,每個(gè)子類都有父類實(shí)例函數(shù)的副本,影響性能
function Parent(name) {
?this.name = name;
?this.colors = ['red', 'blue', 'green'];
}
?
Parent.prototype.getName = function () {
?console.log(this.name)
}
?
function Child(name, age) {
?Parent.call(this, name);
?this.age = age;
}
?
Child.prototype = new Parent();
Child.prototype.constructor = Child;
?
var child1 = new Child('kevin', '18');
child1.colors.push('black');
?
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
?
var child2 = new Child('daisy', '20');
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]
缺點(diǎn):
構(gòu)建原型鏈的時(shí)候,Child.prototype的原型上面會(huì)有name、colors兩個(gè)屬性;在創(chuàng)建child1的時(shí)候它的實(shí)例上也會(huì)有name、colors。實(shí)例對(duì)象child1上的兩個(gè)屬性就屏蔽了其原型對(duì)象Child.prototype的兩個(gè)同名屬性。
所以,組合模式的缺點(diǎn)就是在使用子類創(chuàng)建實(shí)例對(duì)象時(shí),會(huì)調(diào)用兩次父構(gòu)造函數(shù),其原型鏈中會(huì)存在兩份相同的屬性/方法。
原型式繼承
略。不重要可不說(shuō)
寄生式繼承
略。不重要可不說(shuō)
寄生組合式繼承?
對(duì)于組合式繼承的缺點(diǎn),思考一下,如何不調(diào)用兩次父構(gòu)造函數(shù),不使用 Child.prototype = new Parent() ,而是間接的讓 Child.prototype 訪問(wèn)到 Parent.prototype 呢?
function Parent(name) {
?this.name = name;
?this.colors = ['red', 'blue', 'green'];
}
?
Parent.prototype.getName = function () {
?console.log(this.name)
}
?
function Child(name, age) {
?Parent.call(this, name);
?this.age = age;
}
?
// 關(guān)鍵的三步
var F = function () {};
F.prototype = Parent.prototype;
// Child.prototype = new F();
let f = new F()
f.constructor = Child
Child.prototype = f
?
?
?
var child1 = new Child('kevin', '18');
console.log(child1);
最后我們把第三步的方法封裝一下
function object(o) {
?function F() {}
?F.prototype = o;
?return new F();
}
?
function prototype(child, parent) {
?var prototype = object(parent.prototype);
?prototype.constructor = child;
?child.prototype = prototype;
}
?
// 當(dāng)我們使用的時(shí)候:
prototype(Child, Parent);
這種方式的高效率體現(xiàn)它只調(diào)用了一次 Parent 構(gòu)造函數(shù),并且因此避免了在 Parent.prototype 上面創(chuàng)建不必要的、多余的屬性。與此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用 instanceof 和 isPrototypeOf。開發(fā)人員普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式。
ES6類繼承extends?
ES6繼承的原理跟寄生組合式繼承是一樣的。
閉包
定義
-
閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。例如在
javascript
中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以閉包可以理解成定義在一個(gè)函數(shù)內(nèi)部的函數(shù)。在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的橋梁。
優(yōu)缺點(diǎn):
-
能夠訪問(wèn)局部變量
-
保護(hù)局部變量
-
由于閉包
會(huì)將它的外部函數(shù)的作用域也保存在內(nèi)存中
,因此會(huì)比其他函數(shù)更占用內(nèi)存,這樣的話,如果過(guò)度使用閉包,就會(huì)有內(nèi)存泄露的威脅。解決方法——使用完變量后,手動(dòng)將它賦值為null。
應(yīng)用:
-
構(gòu)造函數(shù)的私有屬性。由于javascript中天然沒(méi)有類的實(shí)現(xiàn),某些不希望被外部修改的
私有屬性
可以通過(guò)閉包的方式實(shí)現(xiàn) -
函數(shù)防抖、節(jié)流
瀏覽器的緩存機(jī)制
瀏覽器與服務(wù)器通信的方式為應(yīng)答模式,即是:瀏覽器發(fā)起HTTP請(qǐng)求 – 服務(wù)器響應(yīng)該請(qǐng)求。
-
瀏覽器每次發(fā)起請(qǐng)求,都會(huì)先在瀏覽器緩存中查找該請(qǐng)求的結(jié)果以及緩存標(biāo)識(shí)
-
瀏覽器每次拿到返回的請(qǐng)求結(jié)果都會(huì)將該結(jié)果和緩存標(biāo)識(shí)存入瀏覽器緩存中
根據(jù)是否需要向服務(wù)器重新發(fā)起HTTP請(qǐng)求將緩存過(guò)程分為兩個(gè)部分,分別是強(qiáng)制緩存和協(xié)商緩存。
-
強(qiáng)制緩存就是向?yàn)g覽器緩存查找該請(qǐng)求結(jié)果,并根據(jù)該結(jié)果的緩存規(guī)則來(lái)決定是否使用該緩存結(jié)果的過(guò)程
-
協(xié)商緩存就是強(qiáng)制緩存失效后,瀏覽器攜帶緩存標(biāo)識(shí)向服務(wù)器發(fā)起請(qǐng)求,由服務(wù)器根據(jù)緩存標(biāo)識(shí)決定是否使用緩存的過(guò)程
強(qiáng)制緩存優(yōu)先于協(xié)商緩存進(jìn)行,若強(qiáng)制緩存(Expires和Cache-Control)生效則直接使用緩存,若不生效則進(jìn)行協(xié)商緩存,協(xié)商緩存由服務(wù)器決定是否使用緩存,若協(xié)商緩存失效,那么代表該請(qǐng)求的緩存失效,重新獲取請(qǐng)求結(jié)果,再存入瀏覽器緩存中;生效則返回304,繼續(xù)使用緩存。
任務(wù)隊(duì)列(宏/微任務(wù))
首先我們需要明白以下幾件事情:
-
JS分為同步任務(wù)和異步任務(wù)
-
同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧
-
所謂 "異步",簡(jiǎn)單說(shuō)就是一個(gè)任務(wù)不是連續(xù)完成的,先執(zhí)行第一段,等做好了準(zhǔn)備,再回過(guò)頭執(zhí)行第二段,第二段也被叫做回調(diào);同步則是連貫完成的。
-
主線程之外,有一個(gè)任務(wù)隊(duì)列,只要異步任務(wù)有了運(yùn)行結(jié)果,就在任務(wù)隊(duì)列之中放置一個(gè)事件。
-
一旦執(zhí)行棧中的所有同步任務(wù)執(zhí)行完畢(此時(shí)JS引擎空閑),系統(tǒng)就會(huì)讀取任務(wù)隊(duì)列,將可運(yùn)行的異步任務(wù)添加到可執(zhí)行棧中,開始執(zhí)行。
宏任務(wù)
可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個(gè)宏任務(wù)(包括每次從事件隊(duì)列中獲取一個(gè)事件回調(diào)并放到執(zhí)行棧中執(zhí)行)。
主要包含:script(整體代碼)、setTimeout、setInterval、DOM事件
微任務(wù)
可以理解是在當(dāng)前(主線程)任務(wù)執(zhí)行結(jié)束后立即執(zhí)行的任務(wù)。也就是說(shuō),在當(dāng)前任務(wù)任務(wù)后,下一個(gè)任務(wù)之前,在渲染之前。
所以它的響應(yīng)速度相比setTimeout(setTimeout是task)會(huì)更快,因?yàn)闊o(wú)需等渲染。也就是說(shuō),在某一個(gè)macrotask執(zhí)行完后,就會(huì)將在它執(zhí)行期間產(chǎn)生的所有microtask都執(zhí)行完畢(在渲染前)。
主要包含:Promise.then
運(yùn)行機(jī)制(時(shí)間循環(huán))
在事件循環(huán)中,每進(jìn)行一次循環(huán)操作稱為 tick,每一次 tick 的任務(wù)處理模型是比較復(fù)雜的,但關(guān)鍵步驟如下:
-
執(zhí)行一個(gè)宏任務(wù)(全局Script腳本)
-
產(chǎn)生的的宏任務(wù)和微任務(wù)進(jìn)入各自的隊(duì)列中
-
宏任務(wù)執(zhí)行完畢后,立即執(zhí)行當(dāng)前微任務(wù)隊(duì)列中的所有微任務(wù)(依次執(zhí)行)
-
當(dāng)前宏任務(wù)執(zhí)行完畢,開始檢查渲染,然后GUI線程接管渲染
-
渲染完畢后,JS線程繼續(xù)接管,開始下一個(gè)宏任務(wù)(從事件隊(duì)列中獲?。?/p>
事件委托
利用事件冒泡的原理,將原本綁定給子元素的事件,綁定給父元素,子元素觸發(fā)的事件冒泡給父元素,讓父元素觸發(fā)事件,執(zhí)行函數(shù)。
事件委托好處:1. 效率好;2. 對(duì)于新增的子元素事件依然生效
請(qǐng)求
請(qǐng)求的方式有哪些,應(yīng)用場(chǎng)景是什么
-
GET
GET請(qǐng)求是向服務(wù)端請(qǐng)求獲取某個(gè)或某些資源(resource),比如查詢數(shù)據(jù)庫(kù)單個(gè)或list數(shù)據(jù),服務(wù)端成功的話,一般狀態(tài)碼返回200。
-
POST
POST請(qǐng)求是用來(lái)向服務(wù)端請(qǐng)求新增資源(resource),處理成功的話,服務(wù)端一般返回狀態(tài)碼201。
-
PUT
PUT請(qǐng)求一般是用來(lái)向服務(wù)端請(qǐng)求修改某個(gè)已存在的資源(resource),服務(wù)端一般返回狀態(tài)碼200,204等。
-
DELETE
DELETE請(qǐng)求一般是用來(lái)向服務(wù)端請(qǐng)求刪除某個(gè)已存在的資源(resource),服務(wù)端一般返回200,202等。
-
PATCH
PATCH請(qǐng)求一般是對(duì)某個(gè)資源做局部修改,如個(gè)別字段
什么是promise,解決了什么問(wèn)題
Promise
Promise 是異步編程的一種解決方案:從語(yǔ)法上講,promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息
-
promise有三種狀態(tài): pending(等待態(tài)),fulfiled(成功態(tài)),rejected(失敗態(tài));
-
狀態(tài)一旦改變,就不會(huì)再變。創(chuàng)造promise實(shí)例后,它會(huì)立即執(zhí)行。
-
-
resolve reject都是函數(shù), resolve用來(lái)處理成功的狀態(tài),reject用來(lái)處理失敗的狀態(tài)
-
如何訪問(wèn)promise實(shí)例中的數(shù)據(jù)
-
promise提供了兩個(gè)方法 .then()處理成功 .catch()處理失敗(不會(huì)同時(shí)存在2中狀態(tài))
-
promise基本概念
-
Promise 是一個(gè)構(gòu)造函數(shù)
-
promise.prototype上包含一個(gè) .then 方法
-
.then()方法 可以用來(lái)預(yù)先指定失敗的回調(diào)函數(shù)
-
p.then(成功的回調(diào)函數(shù) ,失敗的回調(diào)函數(shù)) p.then(result=>{},error=>{})
-
調(diào)用p.then()方法時(shí),成功的函數(shù)是必選的 失敗的回調(diào)函數(shù)是可選的
談?wù)剬?duì)async/await的理解
async和await
-
await必須結(jié)合async使用,async通常不會(huì)單獨(dú)使用
-
async表示這個(gè)函數(shù)是一個(gè)異步函數(shù),它的返回值如果是一個(gè)普通數(shù)據(jù)類型,默認(rèn)會(huì)用Promise將數(shù)據(jù)包裹
-
await 等待?等待什么?等待的是一個(gè)異步的結(jié)果
-
異步和同步從上往下的順序執(zhí)行
相對(duì)于promise的優(yōu)點(diǎn):
-
解決了地獄回調(diào)問(wèn)題
-
更簡(jiǎn)潔 更容易調(diào)試 有更好的錯(cuò)誤處理 有條件分支處理
-
處理中間值更簡(jiǎn)單 更清楚異常堆棧來(lái)自哪里
跨越問(wèn)題如何解決
-
同源:2個(gè)頁(yè)面的協(xié)議/域名/端口均相同為同源
-
同源策略 :A網(wǎng)站的js不允許和非同源的網(wǎng)站進(jìn)行資源交互
-
跨域 :協(xié)議/域名/端口不一致時(shí)(會(huì)被瀏覽器攔截)
-
解決方案 :
-
JSONP 和 CORS和代理服務(wù)器
-
CORS:出現(xiàn)的較晚,它是 W3C 標(biāo)準(zhǔn),屬于跨域 Ajax 請(qǐng)求的根本解決方案。支持 GET 和 POST 請(qǐng)求。缺點(diǎn)是不兼容某些低版本的瀏覽器
-
原理: 設(shè)置允許的響應(yīng)頭(需要瀏覽器和服務(wù)器同時(shí)支持).后臺(tái)里面設(shè)置
-
-
JSONP:出現(xiàn)的早,兼容性好(兼容低版本IE)。是前端程序員為了解決跨域問(wèn)題,被迫想出來(lái)的一種臨時(shí)解決方案。
-
原理:根據(jù)< script>標(biāo)簽的src屬性不受瀏覽器同源策略的限制
-
動(dòng)態(tài)創(chuàng)建< script>標(biāo)簽,結(jié)合它的src屬性傳遞可查詢參數(shù)
-
參數(shù)的值是一個(gè)函數(shù)名(函數(shù)名最好隨機(jī)生成,防止變量污染)
-
-
服務(wù)器返回的是一段函數(shù)執(zhí)行代碼
缺點(diǎn)是只支持 GET 請(qǐng)求,不支持 POST 請(qǐng)求。
-
實(shí)現(xiàn)過(guò)程:
-
script標(biāo)簽里的src屬性動(dòng)態(tài)創(chuàng)建和移除
-
在Jsonp請(qǐng)求時(shí),動(dòng)態(tài)向<head>中append(添加)一個(gè)<script>標(biāo)簽
-
在Jsonp請(qǐng)求成功后,動(dòng)態(tài)從<head>中移除剛才append的<script>標(biāo)簽
由于瀏覽器同源策略的限制,網(wǎng)頁(yè)中無(wú)法通過(guò) Ajax 請(qǐng)求非同源的接口數(shù)據(jù)。但是 <script> 標(biāo)簽不受瀏覽器同 源策略的影響,可以通過(guò) src 屬性,請(qǐng)求非同源的 js 腳本。 因此,JSONP 的實(shí)現(xiàn)原理,就是通過(guò) <script> 標(biāo)簽的 src 屬性,請(qǐng)求跨域的數(shù)據(jù)接口,并通過(guò)函數(shù)調(diào)用的形式, 接收跨域接口響應(yīng)回來(lái)的數(shù)據(jù)
-
-
代理服務(wù)器
-
原理: 服務(wù)器和服務(wù)器之前發(fā)送請(qǐng)求不受瀏覽器同源策略的影響
-
在vue.config.js 文件中配置
-
-
輸入網(wǎng)站url地址后發(fā)生了什么
-
URL 解析
-
DNS解析,尋找服務(wù)器(DNS (Domain Name System) 是一個(gè)協(xié)議,主要用途是將一個(gè)域名解析成 IP 地址,這個(gè)過(guò)程叫做域名解析 (Name resolution))
-
TCP連接(傳輸控制協(xié)議(TCP,Transmission Control Protocol)),三次握手
-
第一次:瀏覽器向服務(wù)器發(fā)送請(qǐng)求(SYN=1),等待服務(wù)器確認(rèn);
-
第二次:服務(wù)器收到請(qǐng)求并確認(rèn),回復(fù)一個(gè)指令(SYN=1,ACK=1);
-
第三次:客戶端收到服務(wù)器的回復(fù)指令,并返回確認(rèn)(ACK=1);
-
-
發(fā)送http請(qǐng)求,找到相應(yīng)的資源庫(kù)
-
返回http響應(yīng)(返回?cái)?shù)據(jù))
-
瀏覽器解析渲染頁(yè)面
-
斷開連接
ajax工作流程及原理
-
Ajax的應(yīng)用的五個(gè)步驟:
1、建立XMLHttpRequest對(duì)象;
2、設(shè)置回調(diào)函數(shù);
3、使用open方法與服務(wù)器建立連接;
4、向服務(wù)器端發(fā)送數(shù)據(jù);
5、在回調(diào)函數(shù)針對(duì)不同響應(yīng)狀態(tài)進(jìn)行處理;
-
原理:
ajax的工作原理就是通過(guò)XmlHttpRequest對(duì)象來(lái)向服務(wù)器發(fā)出異步請(qǐng)求,從服務(wù)器中獲得數(shù)據(jù),然后用Javascript來(lái)操作DOM從而更新局部頁(yè)面
axios 是什么、怎么使用
axios 是一個(gè)基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特征:
-
Ajax 是頁(yè)面無(wú)刷新請(qǐng)求數(shù)據(jù)操作
-
從瀏覽器中創(chuàng)建 XMLHttpRequest
-
從 node.js 發(fā)出 http 請(qǐng)求
-
支持 Promise API
-
攔截請(qǐng)求和響應(yīng)
-
轉(zhuǎn)換請(qǐng)求和響應(yīng)數(shù)據(jù)
-
取消請(qǐng)求
-
自動(dòng)轉(zhuǎn)換JSON數(shù)據(jù)
-
客戶端支持防止 CSRF/XSRF
Localstorage、sessionStorage、cookie 的區(qū)別
共同點(diǎn):都是保存在瀏覽器端、且同源的
區(qū)別:
-
請(qǐng)求不同
-
cookie 數(shù)據(jù)始終在同源的 http 請(qǐng)求中攜帶(即使不需要)
-
sessionStorage 和 localStorage不會(huì)自動(dòng)把數(shù)據(jù)發(fā)送給服務(wù)器,僅在本地保存
-
-
存儲(chǔ)大小限制不同
-
cookie 數(shù)據(jù)不能超過(guò) 4K(只適合保存很小的數(shù)據(jù),如會(huì)話標(biāo)識(shí))
-
localStorage和sessionStorage 達(dá)到 5M
-
-
數(shù)據(jù)有效期不同
-
cookie只在設(shè)置的cookie 過(guò)期時(shí)間之前有效,即使窗口關(guān)閉或?yàn)g覽器關(guān)閉
-
localStorage: 始終有效,窗口或?yàn)g覽器關(guān)閉也一直保存,因此用作持久數(shù)據(jù)
-
sessionStorage : 僅在當(dāng)前瀏覽器窗口關(guān)閉之前有效
-
-
作用域不同
-
cookie: 所有同源窗口中都是共享的
-
localStorage: 在所有同源窗口中都是共享的
-
sessionStorage不在不同的瀏覽器窗口中共享,即使是同一個(gè)頁(yè)面
-
-
安全性問(wèn)題
-
如果 cookie 被人攔截了,那人就可以取得所有的 session 信息。即使加密也與事無(wú)補(bǔ),因?yàn)閿r截者并不需要知道 cookie 的意義,他只要原樣轉(zhuǎn)發(fā) cookie 就可以達(dá)到目的了
-
后端接口沒(méi)寫出來(lái),前端如何進(jìn)行開發(fā)
-
mock(模擬接口返回的信息)
-
單純的前端mock可以通過(guò)抓包工具Fiddler,Charles實(shí)現(xiàn)
-
通過(guò)修改代理返回的數(shù)據(jù),實(shí)現(xiàn)多種場(chǎng)景的測(cè)試。這里在抓包工具之中會(huì)解釋
post請(qǐng)求和get請(qǐng)求的區(qū)別
-
get 傳送的數(shù)據(jù)長(zhǎng)度有限制,post 沒(méi)有
-
get 通過(guò) url 傳遞(查詢字符串),在瀏覽器地址欄可見,post 是在請(qǐng)求中傳遞
-
適用場(chǎng)景
-
post 一般用于表單提交
-
get 一般用于簡(jiǎn)單的數(shù)據(jù)查詢,嚴(yán)格要求不是那么高的場(chǎng)景
-
Session,Token,Cookie在身份認(rèn)證方面的區(qū)別
-
為什么要使用身份認(rèn)證:
-
因?yàn)閔ttp協(xié)議是無(wú)狀態(tài)性的,每一次http請(qǐng)求都是獨(dú)立的
-
連續(xù)多個(gè)請(qǐng)求之間無(wú)直接關(guān)系,服務(wù)器不會(huì)主動(dòng)保存每次http請(qǐng)求狀態(tài)
-
-
Session
-
session數(shù)據(jù)放在服務(wù)器上。
-
session會(huì)在一定時(shí)間內(nèi)保存在服務(wù)器上。當(dāng)訪問(wèn)增多,會(huì)比較占用你服務(wù)器的性能
-
將登陸信息等重要信息存放為session
-
-
Cookie
-
cookie數(shù)據(jù)存放在客戶端上(所以安全性不高)
-
所以每個(gè)域的cookie數(shù)量是有限的(比較小4kb)
-
每次發(fā)送請(qǐng)求會(huì)自動(dòng)攜帶Cookie
-
-
Token
-
token是服務(wù)端生成用于驗(yàn)證用戶登錄狀態(tài)的加密數(shù)據(jù),和session驗(yàn)證差不多。
-
token驗(yàn)證服務(wù)端不需要存儲(chǔ)用戶會(huì)話的配置數(shù)據(jù),只是加密的字符串
-
然后用Token設(shè)置請(qǐng)求頭
-
Token的目的是為了減輕服務(wù)器的壓力,減少頻繁的查詢數(shù)據(jù)庫(kù)
-
常見的狀態(tài)碼
-
200:請(qǐng)求已成功
-
401:沒(méi)有權(quán)限
-
402: 參數(shù)傳遞錯(cuò)誤
-
403:服務(wù)器已經(jīng)理解請(qǐng)求,但是拒絕執(zhí)行它。
-
404:請(qǐng)求失敗,請(qǐng)求所希望得到的資源未被在服務(wù)器上發(fā)現(xiàn)。(未找到頁(yè)面)
-
500:服務(wù)器遇到了一個(gè)未曾預(yù)料的狀況,導(dǎo)致了它無(wú)法完成對(duì)請(qǐng)求的處理。一般來(lái)說(shuō),這個(gè)問(wèn)題都會(huì)在服務(wù)器端的源代碼出現(xiàn)錯(cuò)誤時(shí)出現(xiàn)。
Vue2
Vue是什么
是一個(gè)用于創(chuàng)建用戶界面的開源JavaScript框架,也是一個(gè)創(chuàng)建單頁(yè)應(yīng)用的Web應(yīng)用框架。
它的核心特征是數(shù)據(jù)驅(qū)動(dòng)(MVVM)
MVVM
MVVM表示的是Model-View-ViewModel
-
Model:模型層,負(fù)責(zé)處理業(yè)務(wù)邏輯以及和服務(wù)器端進(jìn)行交互
-
View:視圖層:負(fù)責(zé)將數(shù)據(jù)模型轉(zhuǎn)化為UI展示出來(lái),可以簡(jiǎn)單的理解為HTML頁(yè)面
-
ViewModel:視圖模型層,用來(lái)連接Model和View,是Model和View之間的通信橋梁
MVVM就是一種結(jié)構(gòu)設(shè)計(jì)模式。
-
什么是設(shè)計(jì)模式 : 設(shè)計(jì)模式,是對(duì)軟件設(shè)計(jì)中普遍存在的各種問(wèn)題所提出的解決方案
-
mvvm的好處 : 減少DOM操作,提高開發(fā)效率
-
MVVM設(shè)計(jì)模式 : M-model(數(shù)據(jù)模型) V-View(視圖) VM-viewmodel(連接數(shù)據(jù)模型和視圖的對(duì)象,它可以監(jiān)聽數(shù)據(jù)的變化,將數(shù)據(jù)變化映射到視圖,反過(guò)來(lái)也成立)
觀察者模式和發(fā)布訂閱者模式
1、觀察者模式優(yōu)缺點(diǎn)
優(yōu)點(diǎn):模式簡(jiǎn)單,雙方直接通信。
缺點(diǎn):
-
如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。
-
雖然觀察者模式可以隨時(shí)使觀察者知道所觀察的對(duì)象發(fā)生了變化,但是觀察者模式?jīng)]有相應(yīng)的機(jī)制使觀察者知道所觀察的對(duì)象是怎么發(fā)生變化的。
2、發(fā)布訂閱者模式優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
完全解耦特性:消息的發(fā)布者和消息的訂閱者在開發(fā)的時(shí)候完全不需要事先知道對(duì)方的存在,可以獨(dú)立地進(jìn)行開發(fā)。
訂閱者可以只訂閱自己想要的消息
缺點(diǎn):發(fā)布訂閱模式的缺點(diǎn)正是來(lái)源于它的優(yōu)點(diǎn)。通過(guò)從訂閱者中解耦發(fā)布者,它有時(shí)會(huì)很難保證應(yīng)用程序的特定部分按照我們期望的運(yùn)行。倘若我們假設(shè)訂閱者需要記錄或輸出一些與應(yīng)用程序處理有關(guān)的錯(cuò)誤。如果訂閱者執(zhí)行日志崩潰了(或處于某種原因無(wú)法正常運(yùn)行),由于系統(tǒng)的解耦特性,發(fā)布者就不會(huì)看到這一點(diǎn)。
SPA(單頁(yè)應(yīng)用)的理解
single-page application,它通過(guò)動(dòng)態(tài)重寫當(dāng)前頁(yè)面來(lái)與用戶交互,整個(gè)運(yùn)用一個(gè)頁(yè)面。
單頁(yè)面應(yīng)用(SPA) | 多頁(yè)面應(yīng)用(MPA) | |
---|---|---|
組成 | 一個(gè)主頁(yè)面和多個(gè)頁(yè)面片段 | 多個(gè)主頁(yè)面 |
刷新方式 | 局部刷新 | 整頁(yè)刷新 |
url模式 | 哈希模式 | 歷史模式 |
SEO搜索引擎優(yōu)化 | 難實(shí)現(xiàn),可使用SSR方式改善 | 容易實(shí)現(xiàn) |
數(shù)據(jù)傳遞 | 容易 | 通過(guò)url、cookie、localStorage等傳遞 |
頁(yè)面切換 | 速度快,用戶體驗(yàn)良好 | 切換加載資源,速度慢,用戶體驗(yàn)差 |
維護(hù)成本 | 相對(duì)容易 | 相對(duì)復(fù)雜 |
單頁(yè)應(yīng)用優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
-
具有桌面應(yīng)用的即時(shí)性、網(wǎng)站的可移植性和可訪問(wèn)性
-
用戶體驗(yàn)好、快,內(nèi)容的改變不需要重新加載整個(gè)頁(yè)面
-
良好的前后端分離,分工更明確
缺點(diǎn):
-
不利于搜索引擎的抓取
-
首次渲染速度相對(duì)較慢
響應(yīng)式原理
vue.js 是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過(guò)Object.defineProperty()來(lái)劫持各個(gè)屬性的setter, getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。
具體步驟:
第一步:需要 observe 的數(shù)據(jù)對(duì)象進(jìn)行遞歸遍歷,包括子屬性對(duì)象的屬性,都加上 setter 和 getter 這樣的話。給這個(gè)對(duì)象的某個(gè)值賦值,就會(huì)觸發(fā)setter,那么就能監(jiān)聽到了數(shù)據(jù)變化。
第二步:compile解析模板指令,將模板中的變量替換成數(shù)據(jù),然后初始化渲染頁(yè)面視圖,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)有變動(dòng),收到通知,更新視圖
第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是: 1、在自身實(shí)例化時(shí)往屬性訂閱器(dep)里面添加自己 2、自身必須有一個(gè)update()方法 3、待屬性變動(dòng)dep.notice()通知時(shí),能調(diào)用自身的 update()方法,并觸發(fā)Compile中綁定的回調(diào),則功成身退。
第四步:MVVM作為數(shù)據(jù)綁定的入口,整合Observer、Compile和Watcher三者,通過(guò)Observer來(lái)監(jiān)聽自己的 model數(shù)據(jù)變化,通過(guò)Compile來(lái)解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋梁達(dá)到數(shù)據(jù)變化.> 視圖更新:視圖交互變化(input)-> 數(shù)據(jù)model變更的雙向綁定效果.
Vue2生命周期
Vue生命周期總共可以分為8個(gè)階段:創(chuàng)建前后, 載入前后,更新前后,銷毀前銷毀后,以及一些特殊場(chǎng)景的生命周期
生命周期 | 描述 |
---|---|
beforeCreate | 組件實(shí)例被創(chuàng)建之初(初始化vue 實(shí)例,進(jìn)行數(shù)據(jù)觀測(cè)) |
created | 組件實(shí)例已經(jīng)完全創(chuàng)建(完成數(shù)據(jù)觀測(cè),屬性與方法的運(yùn)算,watch 、event 事件回調(diào)的配置) |
beforeMount | 組件掛載之前(處理vm.el) |
mounted | 組件掛載到實(shí)例上去之后(掛載el變成dom) |
beforeUpdate | 組件數(shù)據(jù)發(fā)生變化,更新之前 |
updated | 組件數(shù)據(jù)更新之后 |
beforeDestroy | 組件實(shí)例銷毀之前 |
destroyed | 組件實(shí)例銷毀之后 |
activated | keep-alive 緩存的組件激活時(shí) |
deactivated | keep-alive 緩存的組件停用時(shí)調(diào)用 |
errorCaptured | 捕獲一個(gè)來(lái)自子孫組件的錯(cuò)誤時(shí)被調(diào)用 |
data為什么是函數(shù)的存在
-
產(chǎn)生塊級(jí)作用域--->防止變量污染
-
讓各個(gè)組件實(shí)例維護(hù)各自的數(shù)據(jù)
-
如果單純的寫成對(duì)象形式
-
就使得所有組件實(shí)例共用了一份 data
-
就會(huì)造成一個(gè)變了全都會(huì)變的結(jié)果
-
Vue組件通信的方式
-
通過(guò) props 傳遞
-
通過(guò) $emit 觸發(fā)自定義事件
-
使用 ref
-
EventBus
-
$parent 或$root
-
attrs 與 listeners
-
Provide 與 Inject
-
Vuex
-
vue2.6新增的Vue.observable。一個(gè)小型的狀態(tài)管理器
keep-alive原理及緩存策略
-
Vue.js內(nèi)部在creatd鉤子里將DOM節(jié)點(diǎn)抽象成了一個(gè)個(gè)的VNode節(jié)點(diǎn),keep-alive組件的緩存也是基于VNode節(jié)點(diǎn)的而不是直接存儲(chǔ)DOM結(jié)構(gòu)。
-
它將滿足條件(pruneCache與pruneCache)的組件在cache對(duì)象中緩存起來(lái),在需要重新渲染的時(shí)候再將vnode節(jié)點(diǎn)從cache對(duì)象中取出并渲染。
-
destroyed鉤子則在組件被銷毀的時(shí)候清除cache緩存中的所有組件實(shí)例。
思考題:緩存后如何獲取數(shù)據(jù)?
-
beforeRouteEnter
-
actived
computed原理
computed 也是響應(yīng)式的,給 computed 設(shè)置的 get 和 set 函數(shù),會(huì)跟 Object.defineProperty 關(guān)聯(lián)起來(lái)。所以 Vue 能捕捉到 讀取computed 和 賦值computed 的操作。
計(jì)算屬性是基于它們的依賴進(jìn)行緩存的。計(jì)算屬性只有在它的相關(guān)依賴發(fā)生改變時(shí)才會(huì)重新求值。
首先 computed 計(jì)算后,會(huì)把計(jì)算得到的值保存到一個(gè)變量中。讀取 computed 時(shí)便直接返回這個(gè)變量。當(dāng)使用緩存時(shí),就直接返回這個(gè)變量。當(dāng) computed 更新時(shí),就會(huì)重新賦值更新這個(gè)變量。
computed 控制緩存的重要一點(diǎn)是 【臟數(shù)據(jù)標(biāo)志位 dirty】,dirty 是 watcher 的一個(gè)屬性
當(dāng) dirty 為 true 時(shí),讀取 computed 會(huì)重新計(jì)算
當(dāng) dirty 為 false 時(shí),讀取 computed 會(huì)使用緩存
1一開始每個(gè) computed 新建自己的watcher時(shí),會(huì)設(shè)置 watcher.dirty = true,以便于computed 被使用時(shí),會(huì)計(jì)算得到值
2當(dāng) 依賴的數(shù)據(jù)變化了,通知 computed 時(shí),會(huì)設(shè)置 watcher.dirty = true,以便于其他地方重新渲染,從而重新讀取 computed 時(shí),此時(shí) computed 重新計(jì)算
3computed 計(jì)算完成之后,會(huì)設(shè)置 watcher.dirty = false,以便于其他地方再次讀取時(shí),使用緩存,免于計(jì)算
watch原理
根據(jù) watch 的 api,我們需要了解三個(gè)地方:
1、監(jiān)聽的數(shù)據(jù)改變的時(shí),watch 如何工作
watch 在一開始初始化的時(shí)候,會(huì) 讀取 一遍 監(jiān)聽的數(shù)據(jù)的值,于是,此時(shí) 那個(gè)數(shù)據(jù)就收集到 watch 的 watcher 了
然后 你給 watch 設(shè)置的 handler ,watch 會(huì)放入 watcher 的更新函數(shù)中
當(dāng) 數(shù)據(jù)改變時(shí),通知 watch 的 watcher 進(jìn)行更新,于是 你設(shè)置的 handler 就被調(diào)用了
2、設(shè)置 immediate 時(shí),watch 如何工作
當(dāng)你設(shè)置了 immediate 時(shí),就不需要在 數(shù)據(jù)改變的時(shí)候 才會(huì)觸發(fā)。
而是在 初始化 watch 時(shí),在讀取了 監(jiān)聽的數(shù)據(jù)的值 之后,便立即調(diào)用一遍你設(shè)置的監(jiān)聽回調(diào),然后傳入剛讀取的值
3、設(shè)置了 deep 時(shí),watch 如何工作
-
沒(méi)有設(shè)置 deep
因?yàn)樽x取了監(jiān)聽的 data 的屬性,watch 的 watcher 被收集在 這個(gè)屬性的 收集器中
-
設(shè)置了 deep
因?yàn)樽x取了監(jiān)聽的data 的屬性,watch 的 watcher 被收集在 這個(gè)屬性的 收集器中
在讀取 data 屬性的時(shí)候,發(fā)現(xiàn)設(shè)置了 deep 而且值是一個(gè)對(duì)象,會(huì)遞歸遍歷這個(gè)值,把內(nèi)部所有屬性逐個(gè)讀取一遍,于是 屬性和 它的對(duì)象值內(nèi)每一個(gè)屬性 都會(huì)收集到 watch 的 watcher
于是,無(wú)論對(duì)象嵌套多深的屬性,只要改變了,會(huì)通知 相應(yīng)的 watch 的 watcher 去更新,于是 你設(shè)置的 watch 回調(diào)就被觸發(fā)了
computed和methods、watch的區(qū)別
-
computed是計(jì)算屬性,methods是方法,都可以實(shí)現(xiàn)對(duì) data 中的數(shù)據(jù)加工后再輸出。數(shù)據(jù)量大,需要緩存的時(shí)候用 computed ;每次確實(shí)需要重新加載,不需要緩存時(shí)用 methods 。
-
Watch是一個(gè)偵聽的動(dòng)作,用來(lái)觀察和響應(yīng)Vue實(shí)例上的數(shù)據(jù)變動(dòng)。它們都是vue對(duì)監(jiān)聽器的實(shí)現(xiàn),只不過(guò)computed主要用于對(duì)同步數(shù)據(jù)的處理,watch則主要用于觀測(cè)某個(gè)值的變化去完成一段開銷較大的復(fù)雜業(yè)務(wù)邏輯。
vue-router原理
VueRouter核心是,通過(guò)Vue.use注冊(cè)插件,在插件的install方法中獲取用戶配置的router對(duì)象。當(dāng)瀏覽器地址發(fā)生變化的時(shí)候,根據(jù)router對(duì)象匹配相應(yīng)路由,獲取組件,并將組件渲染到視圖上。
主要有三個(gè)重要點(diǎn):
-
如何在install方法中獲取vue實(shí)例上的router屬性。
可以利用Vue.mixin混入聲明周期函數(shù)beforeCreate,在beforeCreate函數(shù)中可以獲取到Vue實(shí)例上的屬性并賦值到Vue原型鏈上。
_Vue.mixin({
? beforeCreate () {
? ? if (this.$options.router) {
? ? ? _Vue.prototype.$router = this.$options.router
? ? }
? }
})
-
如何觸發(fā)更新
hash模式下:
-
通過(guò)location.hash修改hash值,觸發(fā)更新。
-
通過(guò)監(jiān)聽hashchange事件監(jiān)聽瀏覽器前進(jìn)或者后退,觸發(fā)更新。
history模式下:
-
通過(guò)history對(duì)象方法修改瀏覽器地址,觸發(fā)更新。
-
通過(guò)監(jiān)聽popstate事件監(jiān)聽瀏覽器前進(jìn)或者后退,觸發(fā)更新。
-
如何渲染router-view組件
-
通過(guò)Vue.observable在router實(shí)例上創(chuàng)建一個(gè)保存當(dāng)前路由的監(jiān)控對(duì)象current。
-
當(dāng)瀏覽器地址變化的時(shí)候,修改監(jiān)控對(duì)象current。
-
在router-view組件中監(jiān)聽監(jiān)控對(duì)象current的變化,當(dāng)current變化后,獲取用戶注冊(cè)的相應(yīng)component,并利用h函數(shù)將component渲染成vnodes,進(jìn)而更新頁(yè)面視圖。
Vue3
Vue2和Vue3響應(yīng)式原理的區(qū)別
主要就是Object.defineProperty和Proxy的區(qū)別
Vue3生命周期
選項(xiàng)式API和組合式API
-
組合式 API 的目的是增強(qiáng),不是取代選項(xiàng)式 API , vue3 對(duì)兩種 API 都支持
-
簡(jiǎn)單的場(chǎng)景使用選項(xiàng)式 API 更加簡(jiǎn)單方便
-
需要強(qiáng)烈支持 TS 的項(xiàng)目首選組合式 API
-
需要大量邏輯復(fù)用的場(chǎng)景首選組合式 API
VueX和Pinia的區(qū)別、優(yōu)劣
Pinia的優(yōu)點(diǎn)
-
完整的 TypeScript 支持:與在 Vuex 中添加 TypeScript 相比,添加 TypeScript 更容易
-
極其輕巧(體積約 1KB)
-
store 的 action 被調(diào)度為常規(guī)的函數(shù)調(diào)用,而不是使用 dispatch 方法或 MapAction 輔助函數(shù),這在 Vuex 中很常見
-
支持多個(gè)Store
-
支持 Vue devtools、SSR 和 webpack 代碼拆分
Pinia的缺點(diǎn)
-
不支持時(shí)間旅行和編輯等調(diào)試功能
Vuex的優(yōu)點(diǎn)
-
支持調(diào)試功能,如時(shí)間旅行和編輯
-
適用于大型、高復(fù)雜度的Vue.js項(xiàng)目
Vuex的缺點(diǎn)
-
從 Vue 3 開始,getter 的結(jié)果不會(huì)像計(jì)算屬性那樣緩存
-
Vuex 4有一些與類型安全相關(guān)的問(wèn)題
Vite好在哪為什么
vite優(yōu)點(diǎn):
-
webpack服務(wù)器啟動(dòng)速度比vite慢
由于vite啟動(dòng)的時(shí)候不需要打包,也就無(wú)需分析模塊依賴、編譯,所以啟動(dòng)速度非常快。當(dāng)瀏覽器請(qǐng)求需要的模塊時(shí),再對(duì)模塊進(jìn)行編譯,這種按需動(dòng)態(tài)編譯的模式,極大縮短了編譯時(shí)間,當(dāng)項(xiàng)目越大,文件越多時(shí),vite的開發(fā)時(shí)優(yōu)勢(shì)越明顯
-
vite熱更新比webpack快
vite在HRM方面,當(dāng)某個(gè)模塊內(nèi)容改變時(shí),讓瀏覽器去重新請(qǐng)求該模塊即可,而不是像webpack重新將該模塊的所有依賴重新編譯;
-
vite使用esbuild(Go 編寫) 預(yù)構(gòu)建依賴,而webpack基于nodejs, 比node快 10-100 倍
vite缺點(diǎn):
-
生態(tài)不及webpack,加載器、插件不夠豐富
-
打包到生產(chǎn)環(huán)境時(shí),vite使用傳統(tǒng)的rollup進(jìn)行打包,生產(chǎn)環(huán)境esbuild構(gòu)建對(duì)于css和代碼分割不夠友好。所以,vite的優(yōu)勢(shì)是體現(xiàn)在開發(fā)階段
-
沒(méi)被大規(guī)模重度使用,會(huì)隱藏一些問(wèn)題
-
項(xiàng)目的開發(fā)瀏覽器要支持esmodule
TS
對(duì)ts的理解
-
定義:
添加了類型系統(tǒng)的 JavaScript,適用于任何規(guī)模的項(xiàng)目。類型系統(tǒng)按照「類型檢查的時(shí)機(jī)」來(lái)分類,可以分為動(dòng)態(tài)類型和靜態(tài)類型。
動(dòng)態(tài)類型是指在運(yùn)行時(shí)才會(huì)進(jìn)行類型檢查,這種語(yǔ)言的類型錯(cuò)誤往往會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。JavaScript 是一門解釋型語(yǔ)言,沒(méi)有編譯階段,所以它是動(dòng)態(tài)類型。
靜態(tài)類型是指編譯階段就能確定每個(gè)變量的類型,這種語(yǔ)言的類型錯(cuò)誤往往會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤。TypeScript 在運(yùn)行前需要先編譯為 JavaScript,而在編譯階段就會(huì)進(jìn)行類型檢查,所以 TypeScript 是靜態(tài)類型
-
好處:
項(xiàng)目帶來(lái)更高的可維護(hù)性,以及更少的 bug。
ts的數(shù)據(jù)類型
基礎(chǔ):
布爾值、數(shù)值、字符串、null
、undefined
以及 ES6 中的新類型 Symbol 和 ES10 中的新類型 BigInt。
任意類型:
any、unknown
其他:
元祖、枚舉、void、聯(lián)合類型、類
never和void的區(qū)別
void表示沒(méi)有任何類型,該類型用作函數(shù)的返回值類型。若一個(gè)函數(shù)沒(méi)有返回值,那么該函數(shù)的返回值類型為void類型。
never表示不包含任何值,用永遠(yuǎn)沒(méi)有值
擁有void返回值類型的函數(shù)可以正常運(yùn)行,而never的則無(wú)法執(zhí)行,也無(wú)法終止,會(huì)拋出異常。
枚舉的理解
枚舉是一種數(shù)據(jù)類型,允許我們定義一組命名常量。這樣可以提高代碼的可讀性,便于后續(xù)的維護(hù)。枚舉的使用是通過(guò)enum
關(guān)鍵字進(jìn)行定義。
類型可以分成:
-
數(shù)字枚舉
當(dāng)我們聲明一個(gè)枚舉類型是,雖然沒(méi)有給它們賦值,但是它們的值其實(shí)是默認(rèn)的數(shù)字類型,而且默認(rèn)從0開始依次累加
如果我們將第一個(gè)值進(jìn)行賦值后,后面的值也會(huì)根據(jù)前一個(gè)值進(jìn)行累加1
-
字符串枚舉
-
異構(gòu)枚舉
數(shù)字枚舉和字符串枚舉結(jié)合起來(lái)混合起來(lái)使用
案例:后端的code、0-6對(duì)應(yīng)的日期
泛型
泛型程序設(shè)計(jì)(generic programming)是程序設(shè)計(jì)語(yǔ)言的一種風(fēng)格或范式。
泛型允許我們?cè)趶?qiáng)類型程序設(shè)計(jì)語(yǔ)言中編寫代碼時(shí)使用一些以后才指定的類型,在實(shí)例化時(shí)作為參數(shù)指明這些類型 在typescript
中,定義函數(shù),接口或者類的時(shí)候,不預(yù)先定義好具體的類型,而在使用的時(shí)候在指定類型的一種特性。
泛型通過(guò)<>
的形式進(jìn)行表述,可以聲明:
-
函數(shù)
-
接口
-
類
正確使用泛型可以達(dá)到多類型約束的目的。
項(xiàng)目
token超時(shí)處理
一般有三種處理方式: 前端處理 后端處理 雙token
-
前端處理
-
前端自己設(shè)置一個(gè)token有效期
-
在獲得token的時(shí)候利用cookie-js自帶的方法存入一個(gè)時(shí)間戳
-
在請(qǐng)求攔截器里面做判斷現(xiàn)在的時(shí)間減去存入token的時(shí)間是否超時(shí)了
-
超時(shí)我的處理的是重新登錄(返回登陸頁(yè)面)
-
-
后端處理
-
如果token超時(shí),后端會(huì)返回一個(gè)狀態(tài)碼
-
在響應(yīng)攔截器error中做判斷,看看返回的狀態(tài)碼是否登錄后端返回的這個(gè)token超時(shí)狀態(tài)碼,等于的話就做處理(返回登錄頁(yè)面)
-
-
雙token處理
-
有的時(shí)候登陸成功時(shí)后端會(huì)返回2個(gè)token給我們,一個(gè)是現(xiàn)在用的,一個(gè)是超時(shí)過(guò)后用的
-
如果開始用的token超時(shí)了,那么做處理,調(diào)用第二個(gè)token設(shè)置到請(qǐng)求頭里面
-
如果第二個(gè)也超時(shí)了,做處理(返回登錄頁(yè)面)
-
登錄頁(yè)面安全問(wèn)題
使用md5
插件對(duì)密碼加密
發(fā)布通知功能怎么實(shí)現(xiàn)
websoket
項(xiàng)目剛上線出現(xiàn)bug
版本回退+拉分支出來(lái)修改bug
用什么進(jìn)行版本管理
git
Echarts在Vue里怎么使用
插件v-echarts,注冊(cè)組件使用
Echarts里的配置項(xiàng)不夠用怎么辦
換個(gè)插件,比如螞蟻的AntV
團(tuán)隊(duì)中有的人用vue2有的人用vue3怎么辦
技術(shù)棧選型就確認(rèn)了。下載vue3的版本,在 vue3 中也可以支持 vue2 選項(xiàng)API 寫法。然后在不同的單頁(yè)面里使用不同的語(yǔ)法。
項(xiàng)目?jī)?yōu)化
-
vue優(yōu)化:
-
Vue-Router路由懶加載:Vue異步組件、Webpack的require.ensure()、ES6的import、
-
按需加載UI庫(kù)
-
如果首屏為登錄頁(yè),可以做成多入口
-
頁(yè)面使用骨架屏Skeleton Screen
-
服務(wù)端渲染SSR(將組件或頁(yè)面通過(guò)服務(wù)器生成html字符串,再發(fā)送到瀏覽器,最后將靜態(tài)標(biāo)記"混合"為客戶端上完全交互的應(yīng)用程序)
-
網(wǎng)絡(luò)優(yōu)化:
-
減少 HTTP 請(qǐng)求數(shù)量
-
利用瀏覽器緩存,減小
cookie
大小,盡量用localStorage
代替 -
CDN加速,托管靜態(tài)文件
-
開啟 Gzip 壓縮:Nginx的gzip緩存壓縮、Webpack開啟gzip壓縮
-
js優(yōu)化:
-
節(jié)流、防抖
-
動(dòng)態(tài)加載、分頁(yè)加載(大數(shù)據(jù)渲染)
-
圖片懶加載(data-src)減少占用網(wǎng)絡(luò)帶寬
-
使用閉包時(shí),在函數(shù)結(jié)尾手動(dòng)刪除不需要的局部變量,尤其在緩存dom節(jié)點(diǎn)的情況下
-
異步加載js,async解析dom樹同時(shí)加載js,加載完暫停解析執(zhí)行js、defer解析dom樹同時(shí)加載js,解析完執(zhí)行js
-
css優(yōu)化:
-
不使用css表達(dá)式
-
減少回流(重排)
-
避免使用css文件嵌套過(guò)深
-
SEO優(yōu)化
PC端兼容問(wèn)題
img下的留白
解決方案:給img設(shè)定display:block。
如果圖片加a標(biāo)簽在IE9-中會(huì)有邊框
解決方案:給img設(shè)定border:none。
移動(dòng)端問(wèn)題
移動(dòng)端頁(yè)面滾動(dòng)滯澀感
css在body元素上添加-webkit-overflow-scrolling: touch;
修改移動(dòng)端的點(diǎn)擊高亮效果
* {-webkit-tap-highlight-color:rgba(0,0,0,0);}
滾動(dòng)穿透問(wèn)題
方案一:在html和body上設(shè)置overflow:hidden禁止?jié)L動(dòng)
方案二:阻止touchmove默認(rèn)事件
? ?var modal = document.getElementById('modal'); // 彈窗dom對(duì)象
? ?modal.addEventListener('touchmove', function(e) {
? ? ?e.preventDefault();
? }, false);
方案三:position: fixed
方案一和三,如果需要保持滾動(dòng)條的位置需要用 js 保存滾動(dòng)條位置關(guān)閉的時(shí)候還原滾動(dòng)位置
在ios和andriod中,audio元素和video元素在無(wú)法自動(dòng)播放
應(yīng)對(duì)方案:觸屏即播
? ?$('html').one('touchstart',function(){
? ? ? ?audio.play()
? })
iOS 系統(tǒng)中文輸入法輸入英文時(shí),字母之間可能會(huì)出現(xiàn)一個(gè)六分之一空格
可以通過(guò)正則去掉: this.value = this.value.replace(/\u2006/g, '')
IOS移動(dòng)端click事件300ms的延遲響應(yīng)
引入第三方插件fastclick可以解決在手機(jī)上點(diǎn)擊事件的300ms延遲
阻止旋轉(zhuǎn)屏幕時(shí)自動(dòng)調(diào)整字體大小
html, body, form, fieldset, p, div, h1, h2, h3, h4, h5, h6 {-webkit-text-size-adjust:none;}
圖片模糊問(wèn)題
根據(jù)不一樣的像素比,準(zhǔn)備不一樣的圖片,正常來(lái)說(shuō)是1px圖片像素 對(duì)應(yīng)1px物理像素,圖片的顯示就不會(huì)模糊啦,但是這樣的情況不多,不是非常重要,特殊需求的圖,我們不這么做。
.avatar{
? ?background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
? ?.avatar{
? ? ? ?background-image: url(conardLi_2x.png);
? }
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
? ?.avatar{
? ? ? ?background-image: url(conardLi_3x.png);
? }
}
移動(dòng)端某些情況下input的placeholder會(huì)出現(xiàn)文本位置偏上的現(xiàn)象
PC端設(shè)置line-height等于height能夠?qū)R,而移動(dòng)端仍然是偏上,解決是設(shè)置line-height:normal
h5底部輸入框被鍵盤遮擋問(wèn)題
可以通過(guò)監(jiān)聽移動(dòng)端軟鍵盤彈起,Element.scrollIntoView() 方法讓當(dāng)前的元素滾動(dòng)到瀏覽器窗口的可視區(qū)域內(nèi)。
window.addEventListener('resize', function() { ?
? ?if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') { ? ?
? ? ? ?setTimeout(function() { ? ? ?
? ? ? ? ? ?if ('scrollIntoView' in document.activeElement) { ? ? ? ?
? ? ? ? ? ? ? ?document.activeElement.scrollIntoView(false) ? ? ?
? ? ? ? ? } else { ? ? ? ?
? ? ? ? ? ? ? ?document.activeElement.scrollIntoViewIfNeeded(false) ? ? ?
? ? ? ? ? } ? ?
? ? ? }, 0) ?
? }
})
移動(dòng)端如何做真機(jī)測(cè)試
方式1、公司有測(cè)試服務(wù)器,代碼放到測(cè)試服務(wù)器上,進(jìn)行手機(jī)訪問(wèn)測(cè)試
方式2、自己電腦上搭服務(wù)器,保證自己手機(jī)和電腦處于同一個(gè)局域網(wǎng),然后用手機(jī)進(jìn)行訪問(wèn)測(cè)試
H5和app的區(qū)別
-
H5是通過(guò)鏈接進(jìn)行訪問(wèn),而APP是通過(guò)應(yīng)用程序進(jìn)行訪問(wèn)
-
H5在應(yīng)用商店里面沒(méi)有,而APP是有的
-
H5不需要審核就可以上線,而APP是需要審核的
-
H5的響應(yīng)速度沒(méi)有APP快文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-481485.html
-
H5的開發(fā)成本比APP低文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-481485.html
到了這里,關(guān)于2023前端超全面試題,全是金三銀四面試真題整理!附答案。的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!