目錄javascript
判斷 js 類型的方式
1. typeof
能夠判斷出'string','number','boolean','undefined','symbol'
但判斷 typeof(null) 時值爲 'object'; 判斷數組和對象時值均爲 'object'
css
2. instanceof
原理是 構造函數的 prototype 屬性是否出如今對象的原型鏈中的任何位置html
複製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()
用於判斷是否爲數組java
ES5 和 ES6 分別幾種方式聲明變量
ES5 有倆種:var
和 function
ES6 有六種:增長四種,let
、const
、class
和 import
webpack
注意:let
、const
、class
聲明的全局變量不再會和全局對象的屬性掛鉤css3
閉包的概念?優缺點?
閉包的概念:閉包就是能讀取其餘函數內部變量的函數。git
優勢:web
- 避免全局變量的污染
- 但願一個變量長期存儲在內存中(緩存變量)
缺點:面試
- 內存泄露(消耗)
- 常駐內存,增長內存使用量
淺拷貝和深拷貝
- 淺拷貝
複製// 第一層爲深拷貝 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()
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()
複製// 這種方法會有一個問題:[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
介紹下 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、瀏覽器面試題