目錄
- ES5 和 ES6 分別幾種方式聲明變量
- DOM 事件有哪些階段庇谆?談?wù)剬?duì)事件代理的理解
- ES6 的 class 和構(gòu)造函數(shù)的區(qū)別
- transform凭疮、translate执解、transition 分別是什么屬性?CSS 中常用的實(shí)現(xiàn)動(dòng)畫(huà)方式
- 介紹一下rAF(requestAnimationFrame)
- javascript 的垃圾回收機(jī)制講一下
- 對(duì)前端性能優(yōu)化有什么了解新蟆?一般都通過(guò)那幾個(gè)方面去優(yōu)化的琼稻?
判斷 js 類(lèi)型的方式
1. typeof
可以判斷出'string','number','boolean','undefined','symbol'
但判斷 typeof(null) 時(shí)值為 'object'; 判斷數(shù)組和對(duì)象時(shí)值均為 'object'
2. instanceof
原理是 構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在對(duì)象的原型鏈中的任何位置
復(fù)制function A() {}
let a = new A();
a instanceof A //true,因?yàn)?Object.getPrototypeOf(a) === A.prototype;
Object.prototype.toString.call()
常用于判斷瀏覽器內(nèi)置對(duì)象,對(duì)于所有基本的數(shù)據(jù)類(lèi)型都能進(jìn)行判斷欣簇,即使是 null 和 undefinedArray.isArray()
用于判斷是否為數(shù)組
ES5 和 ES6 分別幾種方式聲明變量
ES5 有倆種:var
和 function
ES6 有六種:增加四種坯约, let
闹丐、 const
、 class
和 import
注意: let 衫仑、 const 文狱、 class 聲明的全局變量再也不會(huì)和全局對(duì)象的屬性掛鉤
閉包的概念缘挽??jī)?yōu)缺點(diǎn)壕曼?
閉包的概念??jī)?yōu)缺點(diǎn)摹蘑?
閉包的概念:閉包就是能讀取其他函數(shù)內(nèi)部變量的函數(shù)衅鹿。
優(yōu)點(diǎn):
1.避免全局變量的污染
2.希望一個(gè)變量長(zhǎng)期存儲(chǔ)在內(nèi)存中(緩存變量)
缺點(diǎn):
內(nèi)存泄露(消耗)
1.常駐內(nèi)存过咬,增加內(nèi)存使用量
2.淺拷貝和深拷貝
淺拷貝
復(fù)制// 第一層為深拷貝
Object.assign()
Array.prototype.slice()
擴(kuò)展運(yùn)算符 ...
深拷貝
復(fù)制JSON.parse(JSON.stringify())
遞歸函數(shù)
復(fù)制function cloneObject(obj) {
var newObj = {} //如果不是引用類(lèi)型援奢,直接返回
if (typeof obj !== 'object') {
return obj
}
//如果是引用類(lèi)型集漾,遍歷屬性
else {
for (var attr in obj) {
//如果某個(gè)屬性還是引用類(lèi)型,遞歸調(diào)用
newObj[attr] = cloneObject(obj[attr])
}
}
return newObj
}
數(shù)組去重的方法
1.ES6 的 Set
復(fù)制let arr = [1,1,2,3,4,5,5,6]
let arr2 = [...new Set(arr)]
2.reduce()
let arr = [1,1,2,3,4,5,5,6]
let arr2 = arr.reduce(function(ar,cur) {
if(!ar.includes(cur)) {
ar.push(cur)
}
return ar
},[])
3.filter()
復(fù)制// 這種方法會(huì)有一個(gè)問(wèn)題:[1,'1']會(huì)被當(dāng)做相同元素纬霞,最終輸入[1]
let arr = [1,1,2,3,4,5,5,6]
let arr2 = arr.filter(function(item,index) {
// indexOf() 方法可返回某個(gè)指定的 字符串值 在字符串中首次出現(xiàn)的位置
return arr.indexOf(item) === index
})
DOM 事件有哪些階段诗芜?談?wù)剬?duì)事件代理的理解
分為三大階段:捕獲階段--目標(biāo)階段--冒泡階段
事件代理簡(jiǎn)單說(shuō)就是:事件不直接綁定到某元素上伏恐,而是綁定到該元素的父元素上,進(jìn)行觸發(fā)事件操作時(shí)(例如'click')横蜒,再通過(guò)條件判斷丛晌,執(zhí)行事件觸發(fā)后的語(yǔ)句(例如'alert(e.target.innerHTML)')
好處:(1)使代碼更簡(jiǎn)潔斗幼;(2)節(jié)省內(nèi)存開(kāi)銷(xiāo)
js 執(zhí)行機(jī)制蜕窿、事件循環(huán)
JavaScript 語(yǔ)言的一大特點(diǎn)就是單線程,同一個(gè)時(shí)間只能做一件事斤贰。單線程就意味著荧恍,所有任務(wù)需要排隊(duì)屯吊,前一個(gè)任務(wù)結(jié)束盒卸,才會(huì)執(zhí)行后一個(gè)任務(wù)。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng)摘投,后一個(gè)任務(wù)就不得不一直等著犀呼。JavaScript 語(yǔ)言的設(shè)計(jì)者意識(shí)到這個(gè)問(wèn)題外臂,將所有任務(wù)分成兩種律胀,一種是 同步任務(wù)(synchronous),另一種是異步任務(wù)(asynchronous) 逛漫,在所有同步任務(wù)執(zhí)行完之前菇民,任何的異步任務(wù)是不會(huì)執(zhí)行的第练。
當(dāng)我們打開(kāi)網(wǎng)站時(shí)玛荞,網(wǎng)頁(yè)的渲染過(guò)程就是一大堆同步任務(wù)勋眯,比如頁(yè)面骨架和頁(yè)面元素的渲染客蹋。而像加載圖片音樂(lè)之類(lèi)占用資源大耗時(shí)久的任務(wù),就是異步任務(wù)番电。關(guān)于這部分有嚴(yán)格的文字定義漱办,但本文的目的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制婉烟,所以我們用導(dǎo)圖來(lái)說(shuō)明:
導(dǎo)圖要表達(dá)的內(nèi)容用文字來(lái)表述的話:
同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行"場(chǎng)所"洞辣,同步的進(jìn)入主線程昙衅,異步的進(jìn)入 Event Table 并注冊(cè)函數(shù)绒尊。當(dāng) 指定的事情完成時(shí) ,Event Table 會(huì)將這個(gè)函數(shù)移入 Event Queue蟹但。主線程內(nèi)的任務(wù)執(zhí)行完畢為空华糖,會(huì)去 Event Queue 讀取對(duì)應(yīng)的函數(shù)客叉,進(jìn)入主線程執(zhí)行。上述過(guò)程會(huì)不斷重復(fù)卵慰,也就是常說(shuō)的 Event Loop(事件循環(huán))裳朋。
我們不禁要問(wèn)了吓著,那怎么知道主線程執(zhí)行棧為空鞍筝骸?js 引擎存在 monitoring process 進(jìn)程罢荡,會(huì)持續(xù)不斷的檢查主線程執(zhí)行棧是否為空区赵,一旦為空笼才,就會(huì)去 Event Queue 那里檢查是否有等待被調(diào)用的函數(shù)络凿。換一張圖片也許更好理解主線程的執(zhí)行過(guò)程:
上圖用文字表述就是:主線程從"任務(wù)隊(duì)列"中讀取事件摔踱,這個(gè)過(guò)程是循環(huán)不斷的怨愤,所以整個(gè)的這種運(yùn)行機(jī)制又稱(chēng)為 Event Loop(事件循環(huán))派敷。只要主線程空了,就會(huì)去讀取"任務(wù)隊(duì)列",這就是 JavaScript 的運(yùn)行機(jī)制篮愉。
說(shuō)完 JS 主線程的執(zhí)行機(jī)制腐芍,下面說(shuō)說(shuō)經(jīng)常被問(wèn)到的 JS 異步中 宏任務(wù)(macrotasks)、微任務(wù)(microtasks)執(zhí)行順序试躏。 JS 異步有一個(gè)機(jī)制猪勇,就是遇到宏任務(wù),先執(zhí)行宏任務(wù)颠蕴,將宏任務(wù)放入 Event Queue泣刹,然后再執(zhí)行微任務(wù)犀被,將微任務(wù)放入 Event Queue椅您,但是,這兩個(gè) Queue 不是一個(gè) Queue弱判。當(dāng)你往外拿的時(shí)候先從微任務(wù)里拿這個(gè)回調(diào)函數(shù)襟沮,然后再?gòu)暮耆蝿?wù)的 Queue 拿宏任務(wù)的回調(diào)函數(shù) 锥惋。如下圖:
宏任務(wù):整體代碼 script昌腰,setTimeout,setInterval
微任務(wù):Promise膀跌,process.nextTick
介紹下 promise.all
Promise.all()方法將多個(gè)Promise實(shí)例包裝成一個(gè)Promise對(duì)象(p)遭商,接受一個(gè)數(shù)組(p1,p2,p3)作為參數(shù),數(shù)組中不一定需要都是Promise對(duì)象捅伤,但是一定具有Iterator接口劫流,如果不是的話,就會(huì)調(diào)用Promise.resolve將其轉(zhuǎn)化為Promise對(duì)象之后再進(jìn)行處理丛忆。
使用Promise.all()生成的Promise對(duì)象(p)的狀態(tài)是由數(shù)組中的Promise對(duì)象(p1,p2,p3)決定的祠汇。
如果所有的Promise對(duì)象(p1,p2,p3)都變成fullfilled狀態(tài)的話,生成的Promise對(duì)象(p)也會(huì)變成fullfilled狀態(tài)熄诡,
p1,p2,p3三個(gè)Promise對(duì)象產(chǎn)生的結(jié)果會(huì)組成一個(gè)數(shù)組返回給傳遞給p的回調(diào)函數(shù)可很。
如果p1,p2,p3中有一個(gè)Promise對(duì)象變?yōu)閞ejected狀態(tài)的話,p也會(huì)變成rejected狀態(tài)凰浮,第一個(gè)被rejected的對(duì)象的返回值會(huì)傳遞給p的回調(diào)函數(shù)我抠。
Promise.all()方法生成的Promise對(duì)象也會(huì)有一個(gè)catch方法來(lái)捕獲錯(cuò)誤處理,但是如果數(shù)組中的Promise對(duì)象變成rejected狀態(tài)時(shí)袜茧,
并且這個(gè)對(duì)象還定義了catch的方法菜拓,那么rejected的對(duì)象會(huì)執(zhí)行自己的catch方法。
并且返回一個(gè)狀態(tài)為fullfilled的Promise對(duì)象笛厦,Promise.all()生成的對(duì)象會(huì)接受這個(gè)Promise對(duì)象纳鼎,不會(huì)返回rejected狀態(tài)。
async 和 await
主要考察宏任務(wù)和微任務(wù),搭配promise喷橙,詢問(wèn)一些輸出的順序
原理:async 和 await 用了同步的方式去做異步啥么,async 定義的函數(shù)的返回值都是 promise,await 后面的函數(shù)會(huì)先執(zhí)行一遍贰逾,然后就會(huì)跳出整個(gè) async 函數(shù)來(lái)執(zhí)行后面js棧的代碼
ES6 的 class 和構(gòu)造函數(shù)的區(qū)別
class 的寫(xiě)法只是語(yǔ)法糖悬荣,和之前 prototype 差不多,但還是有細(xì)微差別的疙剑,下面看看:
嚴(yán)格模式
類(lèi)和模塊的內(nèi)部氯迂,默認(rèn)就是嚴(yán)格模式,所以不需要使用 use strict 指定運(yùn)行模式言缤。只要你的代碼寫(xiě)在類(lèi)或模塊之中嚼蚀,就只有嚴(yán)格模式可用」苄考慮到未來(lái)所有的代碼轿曙,其實(shí)都是運(yùn)行在模塊之中,所以 ES6 實(shí)際上把整個(gè)語(yǔ)言升級(jí)到了嚴(yán)格模式僻孝。不存在提升
類(lèi)不存在變量提升(hoist)导帝,這一點(diǎn)與 ES5 完全不同。
復(fù)制new Foo(); // ReferenceError
class Foo {}
3. 方法默認(rèn)是不可枚舉的
ES6 中的 class穿铆,它的方法(包括靜態(tài)方法和實(shí)例方法)默認(rèn)是不可枚舉的您单,而構(gòu)造函數(shù)默認(rèn)是可枚舉的。細(xì)想一下荞雏,這其實(shí)是個(gè)優(yōu)化虐秦,讓你在遍歷時(shí)候,不需要再判斷 hasOwnProperty 了
4. class 的所有方法(包括靜態(tài)方法和實(shí)例方法)都沒(méi)有原型對(duì)象 prototype凤优,所以也沒(méi)有[[construct]]悦陋,不能使用 new 來(lái)調(diào)用。
5. class 必須使用 new 調(diào)用筑辨,否則會(huì)報(bào)錯(cuò)俺驶。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用 new 也可以執(zhí)行挖垛。
6. ES5 和 ES6 子類(lèi) this 生成順序不同
ES5 的繼承先生成了子類(lèi)實(shí)例痒钝,再調(diào)用父類(lèi)的構(gòu)造函數(shù)修飾子類(lèi)實(shí)例。ES6 的繼承先 生成父類(lèi)實(shí)例痢毒,再調(diào)用子類(lèi)的構(gòu)造函數(shù)修飾父類(lèi)實(shí)例送矩。這個(gè)差別使得 ES6 可以繼承內(nèi)置對(duì)象。
7. ES6可以繼承靜態(tài)方法哪替,而構(gòu)造函數(shù)不能
transform栋荸、translate、transition 分別是什么屬性?CSS 中常用的實(shí)現(xiàn)動(dòng)畫(huà)方式
三者屬性說(shuō)明
transform 是指變換晌块、變形爱沟,是 css3 的一個(gè)屬性,和 width匆背,height 屬性一樣呼伸;
translate 是 transform 的屬性值,是指元素進(jìn)行 2D(3D)維度上位移或范圍變換;
transition 是指過(guò)渡效果钝尸,往往理解成簡(jiǎn)單的動(dòng)畫(huà)括享,需要有觸發(fā)條件。
這里可以補(bǔ)充下 transition 和 animation 的比較珍促,前者一般定義開(kāi)始結(jié)束兩個(gè)狀態(tài)铃辖,需要有觸發(fā)條件;而后者引入了關(guān)鍵幀猪叙、速度曲線娇斩、播放次數(shù)等概念,更符合動(dòng)畫(huà)的定義穴翩,且無(wú)需觸發(fā)條件
介紹一下rAF(requestAnimationFrame)
專(zhuān)門(mén)用來(lái)做動(dòng)畫(huà)犬第,不卡頓,用法和setTimeout一樣藏否。對(duì) rAF 的闡述 MDN 資料
定時(shí)器一直是 js 動(dòng)畫(huà)的核心技術(shù)瓶殃,但它們不夠精準(zhǔn)充包,因?yàn)槎〞r(shí)器時(shí)間參數(shù)是指將執(zhí)行代碼放入 UI 線程隊(duì)列中等待的時(shí)間副签,如果前面有其他任務(wù)隊(duì)列執(zhí)行時(shí)間過(guò)長(zhǎng),則會(huì)導(dǎo)致動(dòng)畫(huà)延遲基矮,效果不精確等問(wèn)題淆储。
所以處理動(dòng)畫(huà)循環(huán)的關(guān)鍵是知道延遲多長(zhǎng)時(shí)間合適:時(shí)間要足夠短,才能讓動(dòng)畫(huà)看起來(lái)比較柔滑平順家浇,避免多余性能損耗本砰;時(shí)間要足夠長(zhǎng),才能讓瀏覽器準(zhǔn)備好變化渲染钢悲。這個(gè)時(shí)候 rAF 就出現(xiàn)了点额,采用系統(tǒng)時(shí)間間隔(大多瀏覽器刷新頻率是 60Hz,相當(dāng)于 1000ms/60≈16.6ms)莺琳,保持最佳繪制效率还棱,不會(huì)因?yàn)殚g隔時(shí)間過(guò)短,造成過(guò)度繪制惭等,增加開(kāi)銷(xiāo)珍手;也不會(huì)因?yàn)殚g隔時(shí)間太長(zhǎng),使用動(dòng)畫(huà)卡頓不流暢,讓各種網(wǎng)頁(yè)動(dòng)畫(huà)效果能夠有一個(gè)統(tǒng)一的刷新機(jī)制琳要。并且 rAF 會(huì)把每一幀中的所有 DOM 操作集中起來(lái)寡具,在一次重繪或回流中就完成。
javascript 的垃圾回收機(jī)制講一下
定義:指一塊被分配的內(nèi)存既不能使用稚补,又不能回收童叠,直到瀏覽器進(jìn)程結(jié)束。
像 C 這樣的編程語(yǔ)言课幕,具有低級(jí)內(nèi)存管理原語(yǔ)拯钻,如 malloc()和 free()。開(kāi)發(fā)人員使用這些原語(yǔ)顯式地對(duì)操作系統(tǒng)的內(nèi)存進(jìn)行分配和釋放撰豺。
而 JavaScript 在創(chuàng)建對(duì)象(對(duì)象粪般、字符串等)時(shí)會(huì)為它們分配內(nèi)存,不再使用對(duì)時(shí)會(huì)“自動(dòng)”釋放內(nèi)存污桦,這個(gè)過(guò)程稱(chēng)為垃圾收集亩歹。
內(nèi)存生命周期中的每一個(gè)階段:
分配內(nèi)存 —? 內(nèi)存是由操作系統(tǒng)分配的,它允許您的程序使用它凡橱。在低級(jí)語(yǔ)言(例如 C 語(yǔ)言)中小作,這是一個(gè)開(kāi)發(fā)人員需要自己處理的顯式執(zhí)行的操作。然而稼钩,在高級(jí)語(yǔ)言中顾稀,系統(tǒng)會(huì)自動(dòng)為你分配內(nèi)在。
使用內(nèi)存 — 這是程序?qū)嶋H使用之前分配的內(nèi)存坝撑,在代碼中使用分配的變量時(shí)静秆,就會(huì)發(fā)生讀和寫(xiě)操作。
釋放內(nèi)存 — 釋放所有不再使用的內(nèi)存,使之成為自由內(nèi)存,并可以被重利用巡李。與分配內(nèi)存操作一樣,這一操作在低級(jí)語(yǔ)言中也是需要顯式地執(zhí)行抚笔。
四種常見(jiàn)的內(nèi)存泄漏:全局變量,未清除的定時(shí)器侨拦,閉包殊橙,以及 dom 的引用
全局變量 不用 var 聲明的變量,相當(dāng)于掛載到 window 對(duì)象上狱从。如:b=1; 解決:使用嚴(yán)格模式
被遺忘的定時(shí)器和回調(diào)函數(shù)
閉包
沒(méi)有清理的 DOM 元素引用
對(duì)前端性能優(yōu)化有什么了解膨蛮?一般都通過(guò)那幾個(gè)方面去優(yōu)化的?
減少請(qǐng)求數(shù)量
減小資源大小
優(yōu)化網(wǎng)絡(luò)連接
優(yōu)化資源加載
減少重繪回流
性能更好的API
webpack優(yōu)化
有想了解更多的小伙伴可以加Q群鏈接里面看一下季研,應(yīng)該對(duì)你們能夠有所幫助敞葛。