目錄
- 判斷 js 型別的方式
- ES5 和 ES6 分別幾種方式宣告變數
- 閉包的概念?優缺點?
- 淺拷貝和深拷貝
- 陣列去重的方法
- DOM 事件有哪些階段?談談對事件代理的理解
- js 執行機制、事件回圈
- 介紹下 promise.all
- async 和 await
- ES6 的 class 和建構式的區別
- transform、translate、transition 分別是什么屬性?CSS 中常用的實作影片方式
- 介紹一下rAF(requestAnimationFrame)
- javascript 的垃圾回識訓制講一下
- 對前端性能優化有什么了解?一般都通過那幾個方面去優化的?
判斷 js 型別的方式
1. typeof
可以判斷出'string','number','boolean','undefined','symbol'
但判斷 typeof(null) 時值為 'object'; 判斷陣列和物件時值均為 'object'
2. instanceof
原理是 建構式的 prototype 屬性是否出現在物件的原型鏈中的任何位置
復制function A() {}
let a = new A();
a instanceof A //true,因為 Object.getPrototypeOf(a) === A.prototype;
3. Object.prototype.toString.call()
常用于判斷瀏覽器內置物件,對于所有基本的資料型別都能進行判斷,即使是 null 和 undefined
4. Array.isArray()
用于判斷是否為陣列
回到頂部ES5 和 ES6 分別幾種方式宣告變數
ES5 有倆種:var 和 function
ES6 有六種:增加四種,let、const、class 和 import
注意:let、const、class宣告的全域變數再也不會和全域物件的屬性掛鉤
閉包的概念?優缺點?
閉包的概念:閉包就是能讀取其他函式內部變數的函式,
優點:
- 避免全域變數的污染
- 希望一個變數長期存盤在記憶體中(快取變數)
缺點:
- 記憶體泄露(消耗)
- 常駐記憶體,增加記憶體使用量
淺拷貝和深拷貝
- 淺拷貝
復制// 第一層為深拷貝
Object.assign()
Array.prototype.slice()
擴展運算子 ...
- 深拷貝
復制JSON.parse(JSON.stringify())
遞回函式
復制function cloneObject(obj) {
var newObj = {} //如果不是參考型別,直接回傳
if (typeof obj !== 'object') {
return obj
}
//如果是參考型別,遍歷屬性
else {
for (var attr in obj) {
//如果某個屬性還是參考型別,遞回呼叫
newObj[attr] = cloneObject(obj[attr])
}
}
return newObj
}
如何實作一個深拷貝
詳細決議賦值、淺拷貝和深拷貝的區別
陣列去重的方法
1.ES6 的 Set
復制let arr = [1,1,2,3,4,5,5,6]
let arr2 = [...new Set(arr)]
2.reduce()
3.filter()
復制// 這種方法會有一個問題:[1,'1']會被當做相同元素,最終輸入[1]
let arr = [1,1,2,3,4,5,5,6]
let arr2 = arr.filter(function(item,index) {
// indexOf() 方法可回傳某個指定的 字串值 在字串中首次出現的位置
return arr.indexOf(item) === index
})
回到頂部DOM 事件有哪些階段?談談對事件代理的理解
分為三大階段:捕獲階段--目標階段--冒泡階段
事件代理簡單說就是:事件不直接系結到某元素上,而是系結到該元素的父元素上,進行觸發事件操作時(例如'click'),再通過條件判斷,執行事件觸發后的陳述句(例如'alert(e.target.innerHTML)')
好處:(1)使代碼更簡潔;(2)節省記憶體開銷
回到頂部js 執行機制、事件回圈
JavaScript 語言的一大特點就是單執行緒,同一個時間只能做一件事,單執行緒就意味著,所有任務需要排隊,前一個任務結束,才會執行后一個任務,如果前一個任務耗時很長,后一個任務就不得不一直等著,JavaScript 語言的設計者意識到這個問題,將所有任務分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous),在所有同步任務執行完之前,任何的異步任務是不會執行的,
當我們打開網站時,網頁的渲染程序就是一大堆同步任務,比如頁面骨架和頁面元素的渲染,而像加載圖片音樂之類占用資源大耗時久的任務,就是異步任務,關于這部分有嚴格的文字定義,但本文的目的是用最小的學習成本徹底弄懂執行機制,所以我們用導圖來說明:

導圖要表達的內容用文字來表述的話:
同步和異步任務分別進入不同的執行"場所",同步的進入主執行緒,異步的進入 Event Table 并注冊函式,當指定的事情完成時,Event Table 會將這個函式移入 Event Queue,主執行緒內的任務執行完畢為空,會去 Event Queue 讀取對應的函式,進入主執行緒執行,上述程序會不斷重復,也就是常說的 Event Loop(事件回圈),
我們不禁要問了,那怎么知道主執行緒執行堆疊為空啊?js 引擎存在 monitoring process 行程,會持續不斷的檢查主執行緒執行堆疊是否為空,一旦為空,就會去 Event Queue 那里檢查是否有等待被呼叫的函式,換一張圖片也許更好理解主執行緒的執行程序:

上圖用文字表述就是:主執行緒從"任務佇列"中讀取事件,這個程序是回圈不斷的,所以整個的這種運行機制又稱為 Event Loop(事件回圈),只要主執行緒空了,就會去讀取"任務佇列",這就是 JavaScript 的運行機制,
說完 JS 主執行緒的執行機制,下面說說經常被問到的 JS 異步中 宏任務(macrotasks)、微任務(microtasks)執行順序,JS 異步有一個機制,就是遇到宏任務,先執行宏任務,將宏任務放入 Event Queue,然后再執行微任務,將微任務放入 Event Queue,但是,這兩個 Queue 不是一個 Queue,當你往外拿的時候先從微任務里拿這個回呼函式,然后再從宏任務的 Queue 拿宏任務的回呼函式,如下圖:

宏任務:整體代碼 script,setTimeout,setInterval
微任務:Promise,process.nextTick
參考鏈接:這一次,徹底弄懂 JavaScript 執行機制
回到頂部介紹下 promise.all
Promise.all()方法將多個Promise實體包裝成一個Promise物件(p),接受一個陣列(p1,p2,p3)作為引數,陣列中不一定需要都是Promise物件,但是一定具有Iterator介面,如果不是的話,就會呼叫Promise.resolve將其轉化為Promise物件之后再進行處理,
使用Promise.all()生成的Promise物件(p)的狀態是由陣列中的Promise物件(p1,p2,p3)決定的,
- 如果所有的Promise物件(p1,p2,p3)都變成fullfilled狀態的話,生成的Promise物件(p)也會變成fullfilled狀態,
p1,p2,p3三個Promise物件產生的結果會組成一個陣列回傳給傳遞給p的回呼函式,
- 如果p1,p2,p3中有一個Promise物件變為rejected狀態的話,p也會變成rejected狀態,第一個被rejected的物件的回傳值會傳遞給p的回呼函式,
Promise.all()方法生成的Promise物件也會有一個catch方法來捕獲錯誤處理,但是如果陣列中的Promise物件變成rejected狀態時,
并且這個物件還定義了catch的方法,那么rejected的物件會執行自己的catch方法,
并且回傳一個狀態為fullfilled的Promise物件,Promise.all()生成的物件會接受這個Promise物件,不會回傳rejected狀態,
回到頂部async 和 await
主要考察宏任務和微任務,搭配promise,詢問一些輸出的順序
原理:async 和 await 用了同步的方式去做異步,async 定義的函式的回傳值都是 promise,await 后面的函式會先執行一遍,然后就會跳出整個 async 函式來執行后面js堆疊的代碼
回到頂部ES6 的 class 和建構式的區別
class 的寫法只是語法糖,和之前 prototype 差不多,但還是有細微差別的,下面看看:
1. 嚴格模式
類和模塊的內部,默認就是嚴格模式,所以不需要使用use strict指定運行模式,只要你的代碼寫在類或模塊之中,就只有嚴格模式可用,考慮到未來所有的代碼,其實都是運行在模塊之中,所以 ES6 實際上把整個語言升級到了嚴格模式,
2. 不存在提升
類不存在變數提升(hoist),這一點與 ES5 完全不同,
復制new Foo(); // ReferenceError
class Foo {}
3. 方法默認是不可列舉的
ES6 中的 class,它的方法(包括靜態方法和實體方法)默認是不可列舉的,而建構式默認是可列舉的,細想一下,這其實是個優化,讓你在遍歷時候,不需要再判斷 hasOwnProperty 了
4. class 的所有方法(包括靜態方法和實體方法)都沒有原型物件 prototype,所以也沒有[[construct]],不能使用 new 來呼叫,
5. class 必須使用 new 呼叫,否則會報錯,這是它跟普通建構式的一個主要區別,后者不用 new 也可以執行,
6. ES5 和 ES6 子類 this 生成順序不同
ES5 的繼承先生成了子類實體,再呼叫父類的建構式修飾子類實體,ES6 的繼承先 生成父類實體,再呼叫子類的建構式修飾父類實體,這個差別使得 ES6 可以繼承內置物件,
7. ES6可以繼承靜態方法,而建構式不能
回到頂部transform、translate、transition 分別是什么屬性?CSS 中常用的實作影片方式
三者屬性說明
transform 是指變換、變形,是 css3 的一個屬性,和 width,height 屬性一樣;
translate 是 transform 的屬性值,是指元素進行 2D(3D)維度上位移或范圍變換;
transition 是指過渡效果,往往理解成簡單的影片,需要有觸發條件,
這里可以補充下 transition 和 animation 的比較,前者一般定義開始結束兩個狀態,需要有觸發條件;而后者引入了關鍵幀、速度曲線、播放次數等概念,更符合影片的定義,且無需觸發條件
回到頂部介紹一下rAF(requestAnimationFrame)
專門用來做影片,不卡頓,用法和setTimeout一樣,對 rAF 的闡述 MDN 資料
定時器一直是 js 影片的核心技術,但它們不夠精準,因為定時器時間引數是指將執行代碼放入 UI 執行緒佇列中等待的時間,如果前面有其他任務佇列執行時間過長,則會導致影片延遲,效果不精確等問題,
所以處理影片回圈的關鍵是知道延遲多長時間合適:時間要足夠短,才能讓影片看起來比較柔滑平順,避免多余性能損耗;時間要足夠長,才能讓瀏覽器準備好變化渲染,這個時候 rAF 就出現了,采用系統時間間隔(大多瀏覽器重繪頻率是 60Hz,相當于 1000ms/60≈16.6ms),保持最佳繪制效率,不會因為間隔時間過短,造成過度繪制,增加開銷;也不會因為間隔時間太長,使用影片卡頓不流暢,讓各種網頁影片效果能夠有一個統一的重繪機制,并且 rAF 會把每一幀中的所有 DOM 操作集中起來,在一次重繪或回流中就完成,
詳情:CSS3影片那么強,requestAnimationFrame還有毛線用?
回到頂部javascript 的垃圾回識訓制講一下
定義:指一塊被分配的記憶體既不能使用,又不能回收,直到瀏覽器行程結束,
像 C 這樣的編程語言,具有低級記憶體管理原語,如 malloc()和 free(),開發人員使用這些原語顯式地對作業系統的記憶體進行分配和釋放,
而 JavaScript 在創建物件(物件、字串等)時會為它們分配記憶體,不再使用對時會“自動”釋放記憶體,這個程序稱為垃圾收集,
記憶體生命周期中的每一個階段:
分配記憶體 —? 記憶體是由作業系統分配的,它允許您的程式使用它,在低級語言(例如 C 語言)中,這是一個開發人員需要自己處理的顯式執行的操作,然而,在高級語言中,系統會自動為你分配內在,
使用記憶體 — 這是程式實際使用之前分配的記憶體,在代碼中使用分配的變數時,就會發生讀和寫操作,
釋放記憶體 — 釋放所有不再使用的記憶體,使之成為自由記憶體,并可以被重利用,與分配記憶體操作一樣,這一操作在低級語言中也是需要顯式地執行,
四種常見的記憶體泄漏:全域變數,未清除的定時器,閉包,以及 dom 的參考
- 全域變數 不用 var 宣告的變數,相當于掛載到 window 物件上,如:b=1; 解決:使用嚴格模式
- 被遺忘的定時器和回呼函式
- 閉包
- 沒有清理的 DOM 元素參考
回到頂部對前端性能優化有什么了解?一般都通過那幾個方面去優化的?
前端性能優化的七大手段
- 減少請求數量
- 減小資源大小
- 優化網路連接
- 優化資源加載
- 減少重繪回流
- 性能更好的API
- webpack優化
前端安全也經常被問到的,常見的有兩種——XSS、CSRF,詳見前端安全
2019前端面試系列——CSS面試題
2019前端面試系列——JS面試題
2019前端面試系列——JS高頻手寫代碼題
2019前端面試系列——Vue面試題
2019前端面試系列——HTTP、瀏覽器面試題
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/47781.html
標籤:JavaScript
