制作精美網(wǎng)站建設(shè)售后完善公司網(wǎng)站建設(shè)服務(wù)機(jī)構(gòu)
1.判斷 js 類型的方式
1. typeof
可以判斷出’string’,‘number’,‘boolean’,‘undefined’,‘symbol’
但判斷 typeof(null) 時(shí)值為 ‘object’; 判斷數(shù)組和對(duì)象時(shí)值均為 ‘object’
2. instanceof
原理是 構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在對(duì)象的原型鏈中的任何位置
function A() {}
let a = new A();
a instanceof A //true,因?yàn)?Object.getPrototypeOf(a) === A.prototype;
3. Object.prototype.toString.call()
常用于判斷瀏覽器內(nèi)置對(duì)象,對(duì)于所有基本的數(shù)據(jù)類型都能進(jìn)行判斷,即使是 null 和 undefined
4. Array.isArray()
用于判斷是否為數(shù)組
2.ES5 和 ES6 分別幾種方式聲明變量
ES5 有倆種: var 和 function
ES6 有六種:增加四種, let 、 const 、 class 和 import
注意: let 、 const 、 class 聲明的全局變量再也不會(huì)和全局對(duì)象的屬性掛鉤
3.閉包的概念?優(yōu)缺點(diǎn)?
閉包的概念:閉包就是能讀取其他函數(shù)內(nèi)部變量的函數(shù)。
優(yōu)點(diǎn):
- 避免全局變量的污染
- 希望一個(gè)變量長(zhǎng)期存儲(chǔ)在內(nèi)存中(緩存變量)
缺點(diǎn): - 內(nèi)存泄露(消耗)
- 常駐內(nèi)存,增加內(nèi)存使用量
4.淺拷貝和深拷貝
- 淺拷貝
// 第一層為深拷貝
Object.assign()
Array.prototype.slice()
擴(kuò)展運(yùn)算符 ...
- 深拷貝
JSON.parse(JSON.stringify())
遞歸函數(shù)
function cloneObject(obj) {
var newObj = {} //如果不是引用類型,直接返回
if (typeof obj !== 'object') {
return obj
}
//如果是引用類型,遍歷屬性
else {
for (var attr in obj) {
//如果某個(gè)屬性還是引用類型,遞歸調(diào)用
newObj[attr] = cloneObject(obj[attr])
}
}
return newObj
}
5.數(shù)組去重的方法
1.ES6 的 Set
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()
// 這種方法會(huì)有一個(gè)問題:[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
})
6.DOM 事件有哪些階段?談?wù)剬?duì)事件代理的理解
分為三大階段:捕獲階段–目標(biāo)階段–冒泡階段
事件代理簡(jiǎn)單說就是:事件不直接綁定到某元素上,而是綁定到該元素的父元素上,進(jìn)行觸發(fā)事件操作
時(shí)(例如’click’),再通過條件判斷,執(zhí)行事件觸發(fā)后的語句(例如’alert(e.target.innerHTML)')
好處:(1)使代碼更簡(jiǎn)潔;(2)節(jié)省內(nèi)存開銷
7.js 執(zhí)行機(jī)制、事件循環(huán)
JavaScript 語言的一大特點(diǎn)就是單線程,同一個(gè)時(shí)間只能做一件事。單線程就意味著,所有任務(wù)需要排
隊(duì),前一個(gè)任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù)。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng),后一個(gè)任務(wù)就不得不一直等
著。JavaScript 語言的設(shè)計(jì)者意識(shí)到這個(gè)問題,將所有任務(wù)分成兩種,一種是同步任務(wù)
(synchronous),另一種是異步任務(wù)(asynchronous),在所有同步任務(wù)執(zhí)行完之前,任何的異步
任務(wù)是不會(huì)執(zhí)行的。
當(dāng)我們打開網(wǎng)站時(shí),網(wǎng)頁的渲染過程就是一大堆同步任務(wù),比如頁面骨架和頁面元素的渲染。而像加
return newObj
}
復(fù)制let arr = [1,1,2,3,4,5,5,6]
let arr2 = […new Set(arr)]
復(fù)制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
},[])
復(fù)制// 這種方法會(huì)有一個(gè)問題:[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
})
載圖片音樂之類占用資源大耗時(shí)久的任務(wù),就是異步任務(wù)。關(guān)于這部分有嚴(yán)格的文字定義,但本文的目
的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制,所以我們用導(dǎo)圖來說明:
導(dǎo)圖要表達(dá)的內(nè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í)行。上述過程會(huì)不斷重復(fù),也就是常說的 Event
Loop(事件循環(huán))。
我們不禁要問了,那怎么知道主線程執(zhí)行棧為空啊?js 引擎存在 monitoring process 進(jìn)程,會(huì)持續(xù)不
斷的檢查主線程執(zhí)行棧是否為空,一旦為空,就會(huì)去 Event Queue 那里檢查是否有等待被調(diào)用的函數(shù)。
換一張圖片也許更好理解主線程的執(zhí)行過程:
上圖用文字表述就是:主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行
機(jī)制又稱為 Event Loop(事件循環(huán))。只要主線程空了,就會(huì)去讀取"任務(wù)隊(duì)列",這就是 JavaScript 的
運(yùn)行機(jī)制。
說完 JS 主線程的執(zhí)行機(jī)制,下面說說經(jīng)常被問到的 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ù),然后再從宏任務(wù)的 Queue 拿宏任務(wù)的回調(diào)函數(shù)。**如
下圖:
宏任務(wù):整體代碼 script,setTimeout,setInterval
微任務(wù):Promise,process.nextTick
參考鏈接:這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制
8.介紹下 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方法來捕獲錯(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)。
9.async 和 await
主要考察宏任務(wù)和微任務(wù),搭配promise,詢問一些輸出的順序
原理:async 和 await 用了同步的方式去做異步,async 定義的函數(shù)的返回值都是 promise,await
后面的函數(shù)會(huì)先執(zhí)行一遍,然后就會(huì)跳出整個(gè) async 函數(shù)來執(zhí)行后面js棧的代碼
10.ES6 的 class 和構(gòu)造函數(shù)的區(qū)別
class 的寫法只是語法糖,和之前 prototype 差不多,但還是有細(xì)微差別的,下面看看:
1. 嚴(yán)格模式
類和模塊的內(nèi)部,默認(rèn)就是嚴(yán)格模式,所以不需要使用 use strict 指定運(yùn)行模式。只要你的代碼寫在
類或模塊之中,就只有嚴(yán)格模式可用??紤]到未來所有的代碼,其實(shí)都是運(yùn)行在模塊之中,所以 ES6 實(shí)
際上把整個(gè)語言升級(jí)到了嚴(yán)格模式。
2. 不存在提升
類不存在變量提升(hoist),這一點(diǎn)與 ES5 完全不同。
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í)例方法)都沒有原型對(duì)象 prototype,所以也沒有
[[construct]],不能使用 new 來調(diào)用。
5. class 必須使用 new 調(diào)用,否則會(huì)報(bào)錯(cuò)。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用 new 也
可以執(zhí)行。
6. ES5 和 ES6 子類 this 生成順序不同
ES5 的繼承先生成了子類實(shí)例,再調(diào)用父類的構(gòu)造函數(shù)修飾子類實(shí)例。ES6 的繼承先 生成父類實(shí)例,再
調(diào)用子類的構(gòu)造函數(shù)修飾父類實(shí)例。這個(gè)差別使得 ES6 可以繼承內(nèi)置對(duì)象。
7. ES6可以繼承靜態(tài)方法,而構(gòu)造函數(shù)不能
11.transform、translate、transition 分別是什么屬性?CSS 中常
用的實(shí)現(xiàn)動(dòng)畫方式
三者屬性說明
transform 是指變換、變形,是 css3 的一個(gè)屬性,和 width,height 屬性一樣;
translate 是 transform 的屬性值,是指元素進(jìn)行 2D(3D)維度上位移或范圍變換;
transition 是指過渡效果,往往理解成簡(jiǎn)單的動(dòng)畫,需要有觸發(fā)條件。
這里可以補(bǔ)充下 transition 和 animation 的比較,前者一般定義開始結(jié)束兩個(gè)狀態(tài),需要有觸發(fā)條件;
而后者引入了關(guān)鍵幀、速度曲線、播放次數(shù)等概念,更符合動(dòng)畫的定義,且無需觸發(fā)條件
12.介紹一下rAF(requestAnimationFrame)
專門用來做動(dòng)畫,不卡頓,用法和setTimeout一樣。對(duì) rAF 的闡述MDN 資料
定時(shí)器一直是 js 動(dòng)畫的核心技術(shù),但它們不夠精準(zhǔn),因?yàn)槎〞r(shí)器時(shí)間參數(shù)是指將執(zhí)行代碼放入 UI 線程
隊(duì)列中等待的時(shí)間,如果前面有其他任務(wù)隊(duì)列執(zhí)行時(shí)間過長(zhǎng),則會(huì)導(dǎo)致動(dòng)畫延遲,效果不精確等問題。
所以處理動(dòng)畫循環(huán)的關(guān)鍵是知道延遲多長(zhǎng)時(shí)間合適:時(shí)間要足夠短,才能讓動(dòng)畫看起來比較柔滑平
順,避免多余性能損耗;時(shí)間要足夠長(zhǎng),才能讓瀏覽器準(zhǔn)備好變化渲染。這個(gè)時(shí)候 rAF 就出現(xiàn)了,采用
系統(tǒng)時(shí)間間隔(大多瀏覽器刷新頻率是 60Hz,相當(dāng)于 1000ms/60≈16.6ms),保持最佳繪制效率,不會(huì)因
為間隔時(shí)間過短,造成過度繪制,增加開銷;也不會(huì)因?yàn)殚g隔時(shí)間太長(zhǎng),使用動(dòng)畫卡頓不流暢,讓各種
網(wǎng)頁動(dòng)畫效果能夠有一個(gè)統(tǒng)一的刷新機(jī)制。并且 rAF 會(huì)把每一幀中的所有 DOM 操作集中起來,在一次
重繪或回流中就完成。
詳情:CSS3動(dòng)畫那么強(qiáng),requestAnimationFrame還有毛線用?
13.javascript 的垃圾回收機(jī)制講一下
定義:指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進(jìn)程結(jié)束。
像 C 這樣的編程語言,具有低級(jí)內(nèi)存管理原語,如 malloc()和 free()。開發(fā)人員使用這些原語顯式地對(duì)
操作系統(tǒng)的內(nèi)存進(jìn)行分配和釋放。
而 JavaScript 在創(chuàng)建對(duì)象(對(duì)象、字符串等)時(shí)會(huì)為它們分配內(nèi)存,不再使用對(duì)時(shí)會(huì)“自動(dòng)”釋放內(nèi)存,這個(gè)
過程稱為垃圾收集。
內(nèi)存生命周期中的每一個(gè)階段:
分配內(nèi)存 — 內(nèi)存是由操作系統(tǒng)分配的,它允許您的程序使用它。在低級(jí)語言(例如 C 語言)中,這是一個(gè)
開發(fā)人員需要自己處理的顯式執(zhí)行的操作。然而,在高級(jí)語言中,系統(tǒng)會(huì)自動(dòng)為你分配內(nèi)在。
使用內(nèi)存 — 這是程序?qū)嶋H使用之前分配的內(nèi)存,在代碼中使用分配的變量時(shí),就會(huì)發(fā)生讀和寫操作。
釋放內(nèi)存 — 釋放所有不再使用的內(nèi)存,使之成為自由內(nèi)存,并可以被重利用。與分配內(nèi)存操作一樣,這一操
作在低級(jí)語言中也是需要顯式地執(zhí)行。
四種常見的內(nèi)存泄漏:全局變量,未清除的定時(shí)器,閉包,以及 dom 的引用
- 全局變量 不用 var 聲明的變量,相當(dāng)于掛載到 window 對(duì)象上。如:b=1; 解決:使用嚴(yán)格模式
- 被遺忘的定時(shí)器和回調(diào)函數(shù)
- 閉包
- 沒有清理的 DOM 元素引用
14.對(duì)前端性能優(yōu)化有什么了解?一般都通過那幾個(gè)方面去優(yōu)化的?
前端性能優(yōu)化的七大手段
1. 減少請(qǐng)求數(shù)量
2. 減小資源大小
3. 優(yōu)化網(wǎng)絡(luò)連接
4. 優(yōu)化資源加載
5. 減少重繪回流
6. 性能更好的API
7. webpack優(yōu)化