為什么虛擬dom會(huì)提高性能?
參考答案
虛擬dom相當(dāng)于在js和真實(shí)dom中間加了一個(gè)緩存,利用dom diff算法避免了沒有必要的dom操作掺炭,從而提高性能。
具體實(shí)現(xiàn)步驟如下:
用 JavaScript 對(duì)象結(jié)構(gòu)表示 DOM 樹的結(jié)構(gòu);然后用這個(gè)樹構(gòu)建一個(gè)真正的 DOM 樹,插到文檔當(dāng)中
當(dāng)狀態(tài)變更的時(shí)候串稀,重新構(gòu)造一棵新的對(duì)象樹。然后用新的樹和舊的樹進(jìn)行比較狮杨,記錄兩棵樹差異
把2所記錄的差異應(yīng)用到步驟1所構(gòu)建的真正的DOM樹上母截,視圖就更新了。
分析比較 opacity: 0橄教、visibility: hidden清寇、display: none 優(yōu)劣和適用場(chǎng)景
參考答案
結(jié)構(gòu):
display:none: 會(huì)讓元素完全從渲染樹中消失,渲染的時(shí)候不占據(jù)任何空間, 不能點(diǎn)擊护蝶,
visibility: hidden:不會(huì)讓元素從渲染樹消失华烟,渲染元素繼續(xù)占據(jù)空間,只是內(nèi)容不可見持灰,不能點(diǎn)擊
opacity: 0: 不會(huì)讓元素從渲染樹消失盔夜,渲染元素繼續(xù)占據(jù)空間,只是內(nèi)容不可見堤魁,可以點(diǎn)擊
繼承:
display: none和opacity: 0:是非繼承屬性喂链,子孫節(jié)點(diǎn)消失由于元素從渲染樹消失造成,通過修改子孫節(jié)點(diǎn)屬性無法顯示妥泉。
visibility: hidden:是繼承屬性涩哟,子孫節(jié)點(diǎn)消失由于繼承了hidden掖疮,通過設(shè)置visibility: visible;可以讓子孫節(jié)點(diǎn)顯式呀页。
性能:
displaynone : 修改元素會(huì)造成文檔回流,讀屏器不會(huì)讀取display: none元素內(nèi)容依许,性能消耗較大
visibility:hidden: 修改元素只會(huì)造成本元素的重繪,性能消耗較少讀屏器讀取visibility: hidden元素內(nèi)容
opacity: 0 :修改元素會(huì)造成重繪,性能消耗較少
聯(lián)系:它們都能讓元素不可見
link與@import的區(qū)別
參考答案
- link是 HTML 方式刽沾, @import是 CSS 方式
- link最大限度支持并行下載瓢剿,@import過多嵌套導(dǎo)致串行下載,出現(xiàn)FOUC
- link可以通過rel="alternate stylesheet"指定候選樣式
- 瀏覽器對(duì)link支持早于@import悠轩,可以使用@import對(duì)老瀏覽器隱藏樣式
- @import必須在樣式規(guī)則之前间狂,可以在 css 文件中引用其他文件
總體來說:link 優(yōu)于@import
清除浮動(dòng)的方式有哪些?比較好的是哪一種?
參考答案
常用的一般為三種:clearfix, clear:both,overflow:hidden;
- 比較好d 是 .clearfix,偽元素萬金油版本,后兩者有局限性.
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
<!--
為毛沒有 zoom ,_height 這些,IE6,7這類需要 csshack 不再我們考慮之內(nèi)了
.clearfix 還有另外一種寫法,
-->
.clearfix:before, .clearfix:after {
content:"";
display:table;
}
.clearfix:after{
clear:both;
overflow:hidden;
}
.clearfix{
zoom:1;
}
<!--
用display:table 是為了避免外邊距margin重疊導(dǎo)致的margin塌陷,
內(nèi)部元素默認(rèn)會(huì)成為 table-cell 單元格的形式
-->
clear:both:若是用在同一個(gè)容器內(nèi)相鄰元素上,那是賊好的,有時(shí)候在容器外就有些問題了, 比如相鄰容器的包裹層元素塌陷
overflow:hidden:這種若是用在同個(gè)容器內(nèi),可以形成 BFC避免浮動(dòng)造成的元素塌陷
img iframe script 來發(fā)送跨域請(qǐng)求有什么優(yōu)缺點(diǎn)?
參考答案
- iframe
優(yōu)點(diǎn):跨域完畢之后DOM操作和互相之間的JavaScript調(diào)用都是沒有問題的
缺點(diǎn):1.若結(jié)果要以URL參數(shù)傳遞火架,這就意味著在結(jié)果數(shù)據(jù)量很大的時(shí)候需要分割傳遞鉴象,巨煩。2.還有一個(gè)是iframe本身帶來的何鸡,母頁面和iframe本身的交互本身就有安全性限制纺弊。 - script
優(yōu)點(diǎn):可以直接返回json格式的數(shù)據(jù),方便處理
缺點(diǎn):只接受GET請(qǐng)求方式 - 圖片img
優(yōu)點(diǎn):可以訪問任何url骡男,一般用來進(jìn)行點(diǎn)擊追蹤淆游,做頁面分析常用的方法
缺點(diǎn):不能訪問響應(yīng)文本,只能監(jiān)聽是否響應(yīng)
http和https的區(qū)別?
參考答案
http傳輸?shù)臄?shù)據(jù)都是未加密的犹菱,也就是明文的拾稳,網(wǎng)景公司設(shè)置了SSL協(xié)議來對(duì)http協(xié)議傳輸?shù)臄?shù)據(jù)進(jìn)行加密處理,簡(jiǎn)單來說https協(xié)議是由http和ssl協(xié)議構(gòu)建的可進(jìn)行加密傳輸和身份認(rèn)證的網(wǎng)絡(luò)協(xié)議腊脱,比http協(xié)議的安全性更高访得。主要的區(qū)別如下:
- Https協(xié)議需要ca證書,費(fèi)用較高陕凹。
- http是超文本傳輸協(xié)議悍抑,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協(xié)議杜耙。
- 使用不同的鏈接方式搜骡,端口也不同,一般而言佑女,http協(xié)議的端口為80浆兰,https的端口為443
- http的連接很簡(jiǎn)單,是無狀態(tài)的珊豹;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議榕订,比http協(xié)議安全店茶。
Cookie、sessionStorage劫恒、localStorage的區(qū)別
參考答案
共同點(diǎn):都是保存在瀏覽器端贩幻,并且是同源的
- Cookie:cookie數(shù)據(jù)始終在同源的http請(qǐng)求中攜帶(即使不需要),即cookie在瀏覽器和服務(wù)器間來回傳遞两嘴。而sessionStorage和localStorage不會(huì)自動(dòng)把數(shù)據(jù)發(fā)給服務(wù)器丛楚,僅在本地保存。cookie數(shù)據(jù)還有路徑(path)的概念憔辫,可以限制cookie只屬于某個(gè)路徑下,存儲(chǔ)的大小很小只有4K左右趣些。(key:可以在瀏覽器和服務(wù)器端來回傳遞,存儲(chǔ)容量小贰您,只有大約4K左右)
- sessionStorage:僅在當(dāng)前瀏覽器窗口關(guān)閉前有效坏平,自然也就不可能持久保持,localStorage:始終有效锦亦,窗口或?yàn)g覽器關(guān)閉也一直保存舶替,因此用作持久數(shù)據(jù);cookie只在設(shè)置的cookie過期時(shí)間之前一直有效杠园,即使窗口或?yàn)g覽器關(guān)閉顾瞪。(key:本身就是一個(gè)回話過程,關(guān)閉瀏覽器后消失,session為一個(gè)回話陈醒,當(dāng)頁面不同即使是同一頁面打開兩次惕橙,也被視為同一次回話)
- localStorage:localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的孵延。(key:同源窗口都會(huì)共享吕漂,并且不會(huì)失效,不管窗口或者瀏覽器關(guān)閉與否都會(huì)始終生效)
補(bǔ)充說明一下cookie的作用:
- 保存用戶登錄狀態(tài)尘应。例如將用戶id存儲(chǔ)于一個(gè)cookie內(nèi)惶凝,這樣當(dāng)用戶下次訪問該頁面時(shí)就不需要重新登錄了,現(xiàn)在很多論壇和社區(qū)都提供這樣的功能犬钢。cookie還可以設(shè)置過期時(shí)間苍鲜,當(dāng)超過時(shí)間期限后,cookie就會(huì)自動(dòng)消失玷犹。因此混滔,系統(tǒng)往往可以提示用戶保持登錄狀態(tài)的時(shí)間:常見選項(xiàng)有一個(gè)月、三個(gè) 月歹颓、一年等坯屿。
- 跟蹤用戶行為。例如一個(gè)天氣預(yù)報(bào)網(wǎng)站巍扛,能夠根據(jù)用戶選擇的地區(qū)顯示當(dāng)?shù)氐奶鞖馇闆r领跛。如果每次都需要選擇所在地是煩瑣的,當(dāng)利用了 cookie后就會(huì)顯得很人性化了撤奸,系統(tǒng)能夠記住上一次訪問的地區(qū)吠昭,當(dāng)下次再打開該頁面時(shí),它就會(huì)自動(dòng)顯示上次用戶所在地區(qū)的天氣情況胧瓜。因?yàn)橐磺卸际窃诤?臺(tái)完成矢棚,所以這樣的頁面就像為某個(gè)用戶所定制的一樣,使用起來非常方便.
- 定制頁面府喳。如果網(wǎng)站提供了換膚或更換布局的功能蒲肋,那么可以使用cookie來記錄用戶的選項(xiàng),例如:背景色钝满、分辨率等肉津。當(dāng)用戶下次訪問時(shí),仍然可以保存上一次訪問的界面風(fēng)格舱沧。
Cookie如何防范XSS攻擊
參考答案
XSS(跨站腳本攻擊)是指攻擊者在返回的HTML中嵌入javascript腳本妹沙,為了減輕這些攻擊,需要在HTTP頭部配上熟吏,set-cookie:
httponly-這個(gè)屬性可以防止XSS,它會(huì)禁止javascript腳本來訪問cookie距糖。
secure - 這個(gè)屬性告訴瀏覽器僅在請(qǐng)求為https的時(shí)候發(fā)送cookie玄窝。
結(jié)果應(yīng)該是這樣的:Set-Cookie=.....
說幾條web前端優(yōu)化策略
參考答案
(1). 減少HTTP請(qǐng)求數(shù)
這條策略基本上所有前端人都知道,而且也是最重要最有效的悍引。都說要減少HTTP請(qǐng)求恩脂,那請(qǐng)求多了到底會(huì)怎么樣呢?首先趣斤,每個(gè)請(qǐng)求都是有成本的俩块,既包 含時(shí)間成本也包含資源成本。一個(gè)完整的請(qǐng)求都需要經(jīng)過DNS尋址浓领、與服務(wù)器建立連接玉凯、發(fā)送數(shù)據(jù)、等待服務(wù)器響應(yīng)联贩、接收數(shù)據(jù)這樣一個(gè)“漫長(zhǎng)”而復(fù)雜的過程漫仆。時(shí)間成本就是用戶需要看到或者“感受”到這個(gè)資源是必須要等待這個(gè)過程結(jié)束的,資源上由于每個(gè)請(qǐng)求都需要攜帶數(shù)據(jù)泪幌,因此每個(gè)請(qǐng)求都需要占用帶寬盲厌。
另外,由于瀏覽器進(jìn)行并發(fā)請(qǐng)求的請(qǐng)求數(shù)是有上限的祸泪,因此請(qǐng)求數(shù)多了以后吗浩,瀏覽器需要分批進(jìn)行請(qǐng)求,因此會(huì)增加用戶的等待時(shí)間没隘,會(huì)給 用戶造成站點(diǎn)速度慢這樣一個(gè)印象懂扼,即使可能用戶能看到的第一屏的資源都已經(jīng)請(qǐng)求完了,但是瀏覽器的進(jìn)度條會(huì)一直存在升略。減少HTTP請(qǐng)求數(shù)的主要途徑包括:
(2). 從設(shè)計(jì)實(shí)現(xiàn)層面簡(jiǎn)化頁面
如果你的頁面像百度首頁一樣簡(jiǎn)單,那么接下來的規(guī)則基本上都用不著了屡限。保持頁面簡(jiǎn)潔品嚣、減少資源的使用時(shí)最直接的。如果不是這樣钧大,你的頁面需要華麗的皮膚翰撑,則繼續(xù)閱讀下面的內(nèi)容。
(3). 合理設(shè)置HTTP緩存
緩存的力量是強(qiáng)大的啊央,恰當(dāng)?shù)木彺嬖O(shè)置可以大大的減少HTTP請(qǐng)求眶诈。以有啊首頁為例,當(dāng)瀏覽器沒有緩存的時(shí)候訪問一共會(huì)發(fā)出78個(gè)請(qǐng)求瓜饥,共600多K 數(shù)據(jù)(如圖1.1)逝撬,而當(dāng)?shù)诙卧L問即瀏覽器已緩存之后訪問則僅有10個(gè)請(qǐng)求,共20多K數(shù)據(jù)(如圖1.2)乓土。(這里需要說明的是宪潮,如果直接F5刷新頁面 的話效果是不一樣的溯警,這種情況下請(qǐng)求數(shù)還是一樣,不過被緩存資源的請(qǐng)求服務(wù)器是304響應(yīng)狡相,只有Header沒有Body梯轻,可以節(jié)省帶寬)
怎樣才算合理設(shè)置?原則很簡(jiǎn)單尽棕,能緩存越多越好喳挑,能緩存越久越好。例如滔悉,很少變化的圖片資源可以直接通過HTTP Header中的Expires設(shè)置一個(gè)很長(zhǎng)的過期頭伊诵;變化不頻繁而又可能會(huì)變的資源可以使用Last-Modifed來做請(qǐng)求驗(yàn)證。盡可能的讓資源能夠 在緩存中待得更久氧敢。
(4). 資源合并與壓縮
如果可以的話日戈,盡可能的將外部的腳本、樣式進(jìn)行合并孙乖,多個(gè)合為一個(gè)浙炼。另外,CSS唯袄、Javascript弯屈、Image都可以用相應(yīng)的工具進(jìn)行壓縮,壓縮后往往能省下不少空間恋拷。
(5). CSS Sprites
合并CSS圖片资厉,減少請(qǐng)求數(shù)的又一個(gè)好辦法。
(6). Inline Images
使用data: URL scheme的方式將圖片嵌入到頁面或CSS中蔬顾,如果不考慮資源管理上的問題的話宴偿,不失為一個(gè)好辦法。如果是嵌入頁面的話換來的是增大了頁面的體積诀豁,而且無法利用瀏覽器緩存窄刘。使用在CSS中的圖片則更為理想一些。
(7). Lazy Load Images
這條策略實(shí)際上并不一定能減少HTTP請(qǐng)求數(shù)舷胜,但是卻能在某些條件下或者頁面剛加載時(shí)減少HTTP請(qǐng)求數(shù)娩践。對(duì)于圖片而言,在頁面剛加載的時(shí)候可以只 加載第一屏烹骨,當(dāng)用戶繼續(xù)往后滾屏的時(shí)候才加載后續(xù)的圖片翻伺。這樣一來,假如用戶只對(duì)第一屏的內(nèi)容感興趣時(shí)沮焕,那剩余的圖片請(qǐng)求就都節(jié)省了吨岭。有啊首頁曾經(jīng)的做法 是在加載的時(shí)候把第一屏之后的圖片地址緩存在Textarea標(biāo)簽中,待用戶往下滾屏的時(shí)候才“惰性”加載峦树。
Promise 構(gòu)造函數(shù)是同步執(zhí)行還是異步執(zhí)行未妹,那么 then 方法呢簿废?
參考答案
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
輸出結(jié)果是:
1
2
4
3
promise構(gòu)造函數(shù)是同步執(zhí)行的,then方法是異步執(zhí)行的
Promise new的時(shí)候會(huì)立即執(zhí)行里面的代碼 then是微任務(wù) 會(huì)在本次任務(wù)執(zhí)行完的時(shí)候執(zhí)行 setTimeout是宏任務(wù) 會(huì)在下次任務(wù)執(zhí)行的時(shí)候執(zhí)行
bind络它、call族檬、apply 區(qū)別?
參考答案
call 和 apply 都是為了解決改變 this 的指向化戳。作用都是相同的单料,只是傳參的方式不同。
除了第一個(gè)參數(shù)外点楼,call 可以接收一個(gè)參數(shù)列表扫尖,apply 只接受一個(gè)參數(shù)數(shù)組。
let a = {
value: 1
}
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.call(a, 'yck', '24')
getValue.apply(a, ['yck', '24'])
bind和其他兩個(gè)方法作用也是一致的掠廓,只是該方法會(huì)返回一個(gè)函數(shù)换怖。并且我們可以通過 bind實(shí)現(xiàn)柯里化。
(下面是對(duì)這三個(gè)方法的擴(kuò)展介紹)
如何實(shí)現(xiàn)一個(gè) bind 函數(shù)
對(duì)于實(shí)現(xiàn)以下幾個(gè)函數(shù)蟀瞧,可以從幾個(gè)方面思考
- 不傳入第一個(gè)參數(shù)沉颂,那么默認(rèn)為 window
- 改變了 this 指向,讓新的對(duì)象可以執(zhí)行該函數(shù)悦污。那么思路是否可以變成給新的對(duì)象添加一個(gè)函數(shù)铸屉,然后在執(zhí)行完以后刪除?
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
var _this = this
var args = [...arguments].slice(1)
// 返回一個(gè)函數(shù)
return function F() {
// 因?yàn)榉祷亓艘粋€(gè)函數(shù)切端,我們可以 new F()彻坛,所以需要判斷
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
如何實(shí)現(xiàn)一個(gè)call函數(shù)
Function.prototype.myCall = function (context) {
var context = context || window
// 給 context 添加一個(gè)屬性
// getValue.call(a, 'yck', '24') => a.fn = getValue
context.fn = this
// 將 context 后面的參數(shù)取出來
var args = [...arguments].slice(1)
// getValue.call(a, 'yck', '24') => a.fn('yck', '24')
var result = context.fn(...args)
// 刪除 fn
delete context.fn
return result
}
如何實(shí)現(xiàn)一個(gè)apply函數(shù)
Function.prototype.myApply = function (context) {
var context = context || window
context.fn = this
var result
// 需要判斷是否存儲(chǔ)第二個(gè)參數(shù)
// 如果存在,就將第二個(gè)參數(shù)展開
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}