高級前端面試題 js篇

2.什么是函數柯里化?

答:是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。

把接受多個參數的函數轉換成接受一個單一參數的函數

// 普通方法varadd =function(x, y){returnx + y;}? ? add(3,4)//7

// 柯里化 var foo = function(x) {

returnfunction(y){returnx + y? ? }}? ? foo(3)(4)// 7? ?

3.什么是Promise對象,有哪些用法?

答: Promise對象的定義

Promise是異步編程的一種解決方案,它是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise

是一個對象,從它可以獲取異步操作的消息。可以用來解決“回調地獄”的問題。Promise 提供統(tǒng)一的

API,各種異步操作都可以用同樣的方法進行處理。promise對象是一個構造函數,用來生成Promise實例; Promise對象的特點

(1)對象的狀態(tài)不受外界影響,promise對象代表一個異步操作,有三種狀態(tài),pending(進行中)、fulfilled(已成功)、rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài),這也是promise這個名字的由來“承若”;

(2)一旦狀態(tài)改變就不會再變,任何時候都可以得到這個結果,promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled,從pending變?yōu)閞ejected。這時就稱為resolved(已定型)。如果改變已經發(fā)生了,你再對promise對象添加回調函數,也會立即得到這個結果,這與事件(event)完全不同,事件的特點是:如果你錯過了它,再去監(jiān)聽是得不到結果的。

有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統(tǒng)一的接口,使得控制異步操作更加容易。

Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執(zhí)行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處于pending狀態(tài)時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

Promise對象的用法

是一個構造函數,這個構造函數里有兩個參數,分別是:resolve(成功之后的回調函數)、reject(失敗之后的回調函數)。

因為promise表示的是一個異步操作,每當我們new一個promise實例,就表示一個具體的異步操作,那么這個異步操作的結果就只能有兩種狀態(tài):成功/失敗,兩者都需要回調函數resolve/reject返回。所以內部拿到操作的結果后,無法使用return把操作結果返回給調用者,這時候只能用回調函數的形式來把成功或失敗的結果返回給調用者。


promise實例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數


then方法可以接受連個回調函數作為參數,第一個回調函數是promise對象的狀態(tài)變?yōu)閞esolved時調用,第二個回調函數是promise對象的狀態(tài)變?yōu)閞ejected時調用,其中,第二個函數是可選的,不一定要提供,這兩個函數都接受promise對象傳出的值作為參數;

*通過。then指定回調函數的時候,成功的回調函數必須傳,失敗的回調函數可以勝利。 如果前面的promise執(zhí)行失敗,不詳影響后續(xù)操作終止,捕獲異常的兩種方式: ①可以為每個promise指定失敗回調;

function(err){ console.log(……) }) ②最后加catch(function(err){

console.log(……) })//表示如前面有任意一個有報錯,立即報錯,并終止后面的;如果前面無報錯,前面正常執(zhí)行。

4.如何通過Promise對象實現(xiàn)ajax?


getJSON是對XMLHTTPRequest對象的封裝,用于發(fā)出一個針對JSON數據的HTTP請求,并且返回一個promise對象,需要注意的是,在getJSON內部,resolve函數和reject函數調用時,都帶有參數;

如果調用resolve函數和reject函數時帶有參數,那么他們的參數會被傳遞給回調函數,reject函數的參數通常是Error對象的實例,表示拋出的錯誤,resolve函數的參數除了正常的值以外,還可以是另一個promise實例;

5.什么是REST,用起來有什么好處?

答:

REST是一種設計API的模式。最常用的數據格式是JSON。由于JSON能直接被JavaScript讀取,所以,以JSON格式編寫的REST風格的API具有簡單、易讀、易用的特點。通過REST模式設計的API可以把web

app 全部功能進行封裝,可以很容易的實現(xiàn)前后端分離,使的前端代碼易編寫,后端代碼易測試。

一直在測試REST模式的WEB SERVICE接口,客戶端的HTTP的請求方式一般分為四種:GET、POST、PUT、DELETE,這四種請求方式有什么不同呢。簡單的說,GET就是獲取資源,POST就是創(chuàng)建資源,PUT就是更新資源,DELETE就是刪除資源。具體來說:

  PUT:PUT請求是向服務器端發(fā)送數據的,從而改變信息,該請求就像數據庫的update操作一樣,用來修改數據的內容,但是不會增加數據的種類等,也就是說無論進行多少次PUT操作,資源不會增加。

  DELETE:DELETE請求顧名思義,就是用來刪除某一個資源的,該請求就像數據庫的delete操作。

  GET:GET操作是安全的。所謂安全是指不管進行多少次操作,資源的狀態(tài)都不會改變,GET只是訪問和查看資源。

  POST:操作不是安全的,每次請求都會創(chuàng)建資源,當我們多次發(fā)出POST請求后,其結果是創(chuàng)建出了多個資源。還有一點需要注意的就是,創(chuàng)建操作可以使用POST,也可以使用PUT,區(qū)別在于POST 是作用在一個集合資源之上的(/uri),而PUT操作是作用在一個具體資源之上的(/uri/xxx),再通俗點說,如果URL可以在客戶端確定,那么就使用PUT,如果是在服務端確定,那么就使用POST,比如說很多資源使用數據庫自增主鍵作為標識信息,而創(chuàng)建的資源的標識信息到底是什么只能由服務端提供,這個時候就必須使用POST。?

  下面說說GET和POST的區(qū)別:

  1、GET請求的數據會附在URL之后(就是把數據放置在HTTP協(xié)議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:getCitycode?lat=100.22&lon=35.33

 POST把提交的數據則放置在是HTTP包的包體中。

2、在瀏覽器上,GET方式提交的數據是有限制的,例如有時候請求的URL太長,會返回錯誤;但如果是客戶端GET請求,是沒有數據的限制的。POST沒有限制,可傳較大量的數據。

3、POST的安全性要比GET的安全性高。這里所說的安全性和上面GET提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作數據修改,而這里安全的含義是真正的Security的含義,比如:通過GET提交數據,用戶名和密碼將明文出現(xiàn)在URL上,查看瀏覽器的歷史紀錄,就可以查看到GET請求的參數,比如登錄的帳號密碼、搜索關鍵字、個人信息等。


PUT和POST方法語義中都有修改資源狀態(tài)的意思,因此都不是安全的。但是PUT方法是冪等的,POST方法不是冪等的,這么設計的理由是:

HTTP協(xié)議規(guī)定,POST方法修改資源狀態(tài)時,URL指示的是該資源的父級資源,待修改資源的ID信息在請求體中攜帶。而PUT方法修改資源狀態(tài)時,URL直接指示待修改資源。因此,同樣是創(chuàng)建資源,重復提交POST請求可能產生兩個不同的資源,而重復提交PUT請求只會對其URL中指定的資源起作用,也就是只會創(chuàng)建一個資源。

6.什么是閉包,舉個例子說明一下?

答:

“閉包就是能夠讀取其他函數內部變量的函數。例如在javascript中,只有函數內部的子函數才能讀取局部變量,所以閉包可以理解成“定義在一個函數內部的函數“。在本質上,閉包是將函數內部和函數外部連接起來的橋梁。”

舉例:創(chuàng)建閉包最常見方式,就是在一個函數內部創(chuàng)建另一個函數。下面例子中的 closure 就是一個閉包, function func(){

vara =1 ,b = 2; funciton closure(){ return a+b; } return

closure; }

7.promise、generator、async/await怎么使用,有什么區(qū)別?

答: 我們知道JavaScript是單線程語言,如果沒有異步編程非得卡死。 以前,異步編程的方法有下面四種 回調函數 事件監(jiān)聽 發(fā)布/訂閱

Promise對象 現(xiàn)在據說異步編程終極解決方案是——async/await 更詳細的介紹參考下面這篇文章:

http://www.lxweimin.com/p/1c9...

8.apply/call/bind 有什么區(qū)別?

答: 這三者的作用就是改變函數運行時this的指向。 call方法: 語法:call([thisObj[,arg1[, arg2[,

[,.argN]]]]]) 定義:調用一個對象的一個方法,以另一個對象替換當前對象。 說明:call

方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對象。

如果沒有提供 thisObj 參數,那么 Global 對象被用作 thisObj。 apply方法: 語法:apply([thisObj[,argArray]]) 定義:應用某一對象的一個方法,用另一個對象替換當前對象。 說明:如果

argArray 不是一個有效的數組或者不是 arguments 對象,那么將導致一個 TypeError。

如果沒有提供 argArray 和 thisObj 任何一個參數,那么Global?對象將被用作 thisObj, 并且無法被傳遞任何參數。bind方法:?語法:bind(thisArg[,?arg1[, arg2[, ...]]])

定義:將接受多個參數的函數變換成接受一個單一參數。

說明:bind()方法所返回的函數的length(形參數量)等于原函數的形參數量減去傳入bind()方法中的實參數量(第一個參數以后的所有參數),因為傳入bind中的實參都會綁定到原函數的形參。

9.什么是變量提升、函數提升?

答: 變量提升:

簡單說就是在js代碼執(zhí)行前引擎會先進行預編譯,預編譯期間會將變量聲明與函數聲明提升至其對應作用域的最頂端,函數內聲明的變量只會提升至該函數作用域最頂層。

當函數內部定義的一個變量與外部相同時,那么函數體內的這個變量就會被上升到最頂端。 舉例來說: console.log(a); //

undefined var a = 3;

//預編譯后的代碼結構可以看做如下運行順序 var a; // 將變量a的聲明提升至最頂端,賦值邏輯不提升。 console.log(a);

// undefined a = 3; // 代碼執(zhí)行到原位置即執(zhí)行原賦值邏輯

函數提升: 函數提升只會提升函數聲明式寫法,函數表達式的寫法不存在函數提升。

函數提升的優(yōu)先級大于變量提升的優(yōu)先級,即函數提升在變量提升之上。

10.什么是事件冒泡,它是如何工作的?如何阻止事件冒泡?

答:

在一個對象上觸發(fā)某類事件(比如單擊onclick事件),如果此對象定義了此事件的處理程序,那么此事件就會調用這個處理程序,如果沒有定義此事件處理程序或者事件返回true,那么這個事件會向這個對象的父級對象傳播,從里到外,直至它被處理(父級對象所有同類事件都將被激活),或者它到達了對象層次的最頂層,即document對象(有些瀏覽器是window)

阻止事件冒泡的幾種方法 第一種: event.stopPropagation(); 第二種: return false; 第三種:

event.preventDefault();

11.簡單說說js中的繼承?

答: 有以下六種方法

1.原型鏈繼承 JavaScript實現(xiàn)繼承的基本思想:通過原型將一個引用類型繼承另一個引用類型的屬性和方法。

2.借用構造函數繼承(偽造對象或經典繼承) JavaScript實現(xiàn)繼承的基本思想:在子類構造函數內部調用超類型構造函數。 通過使用apply()和call()方法可以在新創(chuàng)建的子類對象上執(zhí)行構造函數。

3.組合繼承(原型+借用構造)(偽經典繼承) JavaScript實現(xiàn)繼承的基本思想:將原型鏈和借用構造函數的技術組合在一塊,從而發(fā)揮兩者之長的一種繼承模式。

將原型鏈和借用構造函數的技術組合到一起,從而取長補短發(fā)揮兩者長處的一種繼承模式。

4.原型式繼承 JavaScript實現(xiàn)繼承的基本思想:借助原型可以基于已有的對象創(chuàng)建新對象,同時還不必須因此創(chuàng)建自定義的類型。

5.寄生式繼承 JavaScript實現(xiàn)繼承的基本思想:創(chuàng)建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后再像真正是它做了所有工作一樣返回對象。

寄生式繼承是原型式繼承的加強版。

6.寄生組合式繼承 JavaScript實現(xiàn)繼承的基本思想:通過借用函數來繼承屬性,通過原型鏈的混成形式來繼承方法。

12.常用的js數組操作方法有哪些?

答:

Array.shift()------刪除并返回第一個元素 作用:從數組中刪除第一個元素(即下標為0的元素),并返回該元素。 注意:1)刪除元素之后,數組的長度-1。

2)如果數組是空的,那么 shift() 方法將不進行任何操作,返回undefined值。

2.Array.pop()------刪除并返回最后一個元素 作用:從數組中刪除最后一個元素(即下標為length-1的元素),并返回該元素。 注意:1)刪除元素之后,數組的長度-1。

2)如果數組是空的,那么 shift() 方法將不進行任何操作,返回undefined值。

Array.push(param1[,param2,...paramN])------尾部添加元素 作用:在數組的尾部添加一個元素,并返回新數組的長度。 注意:1)它是直接修改該數組,而不是重新創(chuàng)建一個數組。

2)它和pop是一對相反的先進后出的棧功能方法。3)它可以同時給一個數組添加多個元素。

Array.unshift(newElement1[,newElement2,...newElementN])------頭部添加元素 作用:在數組的頭部添加一個或多個元素,并返回新數組的長度。 注意:1)它是直接修改該數組,而不是重新創(chuàng)建一個數組。

2)IE瀏覽器不支持該方法。

5.Array.join([separator])------轉換成字符串 作用:把數組的所有元素放入到一個字符串中。 注意:1)參數separator表示字符串中元素的分隔符,可以為空,默認為半角逗號。

2)該方法并不修改數組。

Array.contact(array1[,array2,...arrayN])------連接數組 作用:將兩個或兩個以上的數組連接成一個數組,并返回連接后的數組。 注意:1)該方法并不會改變現(xiàn)有的數組,而是返回被連接的多個數組的一個副本。

2)如果多個數組里有值相同的元素,那也不會重復出現(xiàn),而不會把重復的元素過濾掉。

7.Array.reverse()------反轉數組 作用:把數組的所有元素順序反轉。 注意:1)該方法會直接修改數組,而不會創(chuàng)建新的數組。

Array.slice(start[, end])------截取數組 作用:截取數組中指定位置的元素,并返回一個新的子數組。 注意:1)該方法并不會改變現(xiàn)有的數組,而是原數組的一個子數組。

2)參數start是必選,表示開始下標,如果start為負數,表示從末尾開始,-1表示最后一個元素,依次類推。

3)end是可選表示結束下標,如果沒有指定,表示到結尾元素。

9.Array.splice()------刪除指定元素 作用:從數組指定位置刪除指定數量的元素,并返回被刪除的元素。 注意:1)該方法會直接修改數組。

2)splice()?方法與slice()?方法的作用是不同的,splice()?方法會直接對數組進行修改,而slice只是截取原數組的一部分后返回一個子數組,并不會修改原數組。

Array.toString()------轉換成字符串 作用:數組轉換為字符串,并返回該字符串。 注意:1)該方法和不帶參數的join()方法效果一樣。

13.js數組去重,能用幾種方法實現(xiàn)?

答:

1.使用es6 set方法 [...new Set(arr)] let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique = (arr)=> [...new Set(arr)]; unique(arr);//[1, 2, 3, 4, 6, 7]

2.利用新數組indexOf查找 indexOf() 方法可返回某個指定的元素在數組中首次出現(xiàn)的位置。如果沒有就返回-1。

3.for 雙重循環(huán) 通過判斷第二層循環(huán),去重的數組中是否含有該元素,如果有就退出第二層循環(huán),如果沒有j==result.length就相等,然后把對應的元素添加到最后的數組里面。

let arr = [1,2,3,4,3,2,3,4,6,7,6]; let result = []; for(var i = 0 ; i

< arr.length; i++) {

for(varj =0; j

4.利用for嵌套for,然后splice去重 functionunique(arr){ for(vari=0; i

//第一個等同于第二個,splice方法刪除第二個 arr.splice(j,1); j--; } } } returnarr; }

5.利用filter let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique = (arr) => {

returnarr.filter((item,index)=>{returnarr.indexOf(item) === index;}) }; unique(arr);

5.let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique = (arr) => {

returnarr.filter((item,index)=>{returnarr.indexOf(item) === index;}) }; unique(arr);

6.利用Map數據結構去重 let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique = (arr)=> {

letseen =newMap();returnarr.filter((item) =>{return!seen.has(item) && seen.set(item,1);}); }; unique(arr);

14.數組中的forEach和map的區(qū)別?

答: 相同點 都是循環(huán)遍歷數組中的每一項

forEach和map方法里每次執(zhí)行匿名函數都支持3個參數,參數分別是item(當前每一項),index(索引值),arr(原數組)

匿名函數中的this都是指向window 只能遍歷數組 都不會改變原數組 區(qū)別 map方法

1.map方法返回一個新的數組,數組中的元素為原始數組調用函數處理后的值。

2.map方法不會對空數組進行檢測,map方法不會改變原始數組。

3.瀏覽器支持:chrome、Safari1.5+、opera都支持,IE9+, 若arr為空數組,則map方法返回的也是一個空數組。 forEach方法

1.forEach方法用來調用數組的每個元素,將元素傳給回調函數

2.forEach對于空數組是不會調用回調函數的。 無論arr是不是空數組,forEach返回的都是undefined。這個方法只是將數組中的每一項作為callback的參數執(zhí)行一次。

15.jQueryajax 、fetch、 axios 有什么異同,適用場景有哪些?

答:

1.jQuery ajax $.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function ()

{} }); 優(yōu)缺點: 本身是針對MVC的編程,不符合現(xiàn)在前端MVVM的浪潮

JQuery整個項目太大,單純使用ajax卻要引入整個JQuery非常的不合理(采取個性化打包的方案又不能享受CDN服務)

2.axios axios({

method:'post',url:'/user/12345',data:{firstName:'Fred',lastName:'Flintstone'} }) .then(function(response){console.log(response); }) 客戶端支持防止CSRF/XSRF 自動轉換JSON數據 取消請求 轉換請求和響應數據 攔截請求和響應 支持PromiseAPI 從node.js 發(fā)出http 請求 從瀏覽器中創(chuàng)建

XMLHttpRequest axios 是一個基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特征:

為什么要用axios? 4)fetch沒有辦法原生監(jiān)測請求的進度,而XHR可以

3)fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現(xiàn)的超時控制并不能阻止請求過程繼續(xù)在后臺運行,造成了量的浪費

2)fetch默認不會帶cookie,需要添加配置項 1)fetchtch只對網絡請求報錯,對400,500都當做成功的請求,需要封裝去處理

脫離了XHR,是ES規(guī)范里新的實現(xiàn)方式 更加底層,提供的API豐富(request, response) 更好更方便的寫法

符合關注分離,沒有將輸入、輸出和用事件來跟蹤的狀態(tài)混雜在一個對象里 優(yōu)缺點: } console.log("Oops,

error", e); } catch(e) { console.log(data); let data =

response.json(); let response = await fetch(url); try {

3.fetch 提供了一些并發(fā)請求的接口(重要,方便了很多的操作) 客戶端支持防止CSRF 支持 Promise API 從 node.js 創(chuàng)建 http 請求 優(yōu)缺點: });

console.log(error); .catch(function(error){ })

16.es6 擴展運算符可以解決哪些問題?

答: .. 代表著擴展運算符或Rest(剩余)運算符

17.是么是js事件循環(huán) event loop?

答: 主線程從"任務隊列"中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環(huán))。

這里推薦一下阮一峰老師的這篇講解event

loop的博文:http://www.ruanyifeng.com/blo...

講的比較詳細,深入淺出很容易理解。

18.Math.min()和Math.max()大小比較?

答: Math.max() < Math.min() Math.min()如果沒有參數,則返回 Infinity。Infinity 是

javascript 中全局對象的一個屬性,在瀏覽器環(huán)境中就是 window 對象的一個屬性,表示無窮大。 而 Math.max()

沒有傳遞參數時返回的是 -Infinity。 因此 Math.min() 要比 Math.max() 大。

19.怎么實現(xiàn)對象的深淺拷貝?

答: 淺拷貝很容易,只需要使用賦值運算符(=)即可

20.文件上傳如何做斷點續(xù)傳?

答: 文件斷點續(xù)傳是HTML5引入的新特性,HTML5的FILE

api,有一個slice方法,可以將BLOB對象進行分割。前端通過FileList對象獲取到相應的文件,按照指定的分割方式將大文件分段,然后一段一段地傳給后端,后端再按順序一段段將文件進行拼接。

斷點續(xù)傳原理

目前比較常用的斷點續(xù)傳的方法有兩種,一種是通過websocket接口進行文件上傳,另一種是通過ajax,兩種方法各有千秋,雖然websocket聽起來比較高端些,但是除了用了不同的協(xié)議外其他的算法基本上都是很相似的,并且服務端要開啟ws接口,這里用相對方便的ajax來說明斷點上傳的思路。

說來說去,斷點續(xù)傳最核心的內容就是把文件“切片”然后再一片一片的傳給服務器。

首先是文件的識別,一個文件被分成了若干份之后如何告訴服務器你切了多少塊,以及最終服務器應該如何把你上傳上去的文件進行合并?

因此在文件開始上傳之前,我們和服務器要有一個“握手”的過程,告訴服務器文件信息,然后和服務器約定切片的大小,當和服務器達成共識之后就可以開始后續(xù)的文件傳輸了。

前臺要把每一塊的文件傳給后臺,成功之后前端和后端都要標識一下,以便后續(xù)的斷點。

當文件傳輸中斷之后用戶再次選擇文件就可以通過標識來判斷文件是否已經上傳了一部分,如果是的話,那么我們可以接著上次的進度繼續(xù)傳文件,以達到續(xù)傳的功能。

21.js如何處理防抖和節(jié)流?

答:

在進行窗口的resize、scroll,輸入框內容校驗等操作時,如果事件處理函數調用的頻率無限制,會加重瀏覽器的負擔,導致用戶體驗非常糟糕。

此時我們可以采用debounce(防抖)和throttle(節(jié)流)的方式來減少調用頻率,同時又不影響實際效果。 函數防抖

函數防抖(debounce):當持續(xù)觸發(fā)事件時,一定時間段內沒有再觸發(fā)事件,事件處理函數才會執(zhí)行一次,如果設定的時間到來之前,又一次觸發(fā)了事件,就重新開始延時。

如下,持續(xù)觸發(fā)scroll事件時,并不執(zhí)行handle函數,當1000毫秒內沒有觸發(fā)scroll事件時,才會延時觸發(fā)scroll事件。

function debounce(fn, wait) {

vartimeout =null;returnfunction(){if(timeout !==null) clearTimeout(timeout);? ? ? ? ? timeout = setTimeout(fn, wait);? } }// 處理函數 function handle() {? console.log(Math.random()); }// 滾動事件 window.addEventListener('scroll', debounce(handle, 1000)); 函數節(jié)流

函數節(jié)流(throttle):當持續(xù)觸發(fā)事件時,保證一定時間段內只調用一次事件處理函數。

節(jié)流通俗解釋就比如我們水龍頭放水,閥門一打開,水嘩嘩的往下流,秉著勤儉節(jié)約的優(yōu)良傳統(tǒng)美德,我們要把水龍頭關小點,最好是如我們心意按照一定規(guī)律在某個時間間隔內一滴一滴的往下滴。

如下,持續(xù)觸發(fā)scroll事件時,并不立即執(zhí)行handle函數,每隔1000毫秒才會執(zhí)行一次handle函數。 var throttle =

function(func, delay) {

varprev =Date.now();returnfunction(){varcontext =this;varargs =arguments;varnow =Date.now();if(now - prev >= delay) {? ? ? ? ? ? ? ? ? ? ? ? ? func.apply(context, args);? ? ? ? ? ? ? ? ? ? ? ? ? prev =Date.now();? ? ? ? ? ? ? ? ? }? ? ? ? ? }? ? ? ? }functionhandle(){console.log(Math.random());? ? ? ? }window.addEventListener('scroll', throttle(handle,1000)); 總結

函數防抖:將幾次操作合并為一此操作進行。原理是維護一個計時器,規(guī)定在delay時間后觸發(fā)函數,但是在delay時間內再次觸發(fā)的話,就會取消之前的計時器而重新設置。這樣一來,只有最后一次操作能被觸發(fā)。

函數節(jié)流:使得一定時間內只觸發(fā)一次函數。原理是通過判斷是否到達一定時間來觸發(fā)函數。 區(qū)別:

函數節(jié)流不管事件觸發(fā)有多頻繁,都會保證在規(guī)定時間內一定會執(zhí)行一次真正的事件處理函數,而函數防抖只是在最后一次事件后才觸發(fā)一次函數。比如在頁面的無限加載場景下,我們需要用戶在滾動頁面時,每隔一段時間發(fā)一次

Ajax 請求,而不是在用戶停下滾動頁面操作時才去請求數據。這樣的場景,就適合用節(jié)流技術來實現(xiàn)。

22.事件委托以及優(yōu)缺點?

答: 優(yōu)點:

1.減少事件注冊,節(jié)省內存。比如,

2.在table上代理所有td的click事件。

3.在ul上代理所有l(wèi)i的click事件。

4.簡化了dom節(jié)點更新時,相應事件的更新。比如

5.不用在新添加的li上綁定click事件。

6.當刪除某個li時,不用移解綁上面的click事件。 缺點:

1.事件委托基于冒泡,對于不冒泡的事件不支持。

2.層級過多,冒泡過程中,可能會被某層阻止掉。

3.理論上委托會導致瀏覽器頻繁調用處理函數,雖然很可能不需要處理。所以建議就近委托,比如在table上代理td,而不是在document上代理td。

4.把所有事件都用代理就可能會出現(xiàn)事件誤判。比如,在document中代理了所有button的click事件,另外的人在引用改js時,可能不知道,造成單擊button觸發(fā)了兩個click事件。

23.介紹this各種情況?

答:

this的情況:

1.以函數形式調用時,this永遠都是window

2.以方法的形式調用時,this是調用方法的對象

3.以構造函數的形式調用時,this是新創(chuàng)建的那個對象

4.使用call和apply調用時,this是指定的那個對象

5.箭頭函數:箭頭函數的this看外層是否有函數

如果有,外層函數的this就是內部箭頭函數的this如果沒有,就是window

6.特殊情況:通常意義上this指針指向為最后調用它的對象。這里需要注意的一點就是如果返回值是一個對象,那么this指向的就是那個返回的對象,如果返回值不是一個對象那么this還是指向函數的實例

24.== 和 ===的區(qū)別,什么情況下用相等==?

答:

==:運算符稱作相等,用來檢測兩個操作數是否相等,這里的相等定義的非常寬松,可以允許進行類型轉換

===:用來檢測兩個操作數是否嚴格相等 1、對于string,number等基礎類型,==和===是有區(qū)別的 不同類型間比較,==之比較“轉化成同一類型后的值”看“值”是否相等,===如果類型不同,其結果就是不等

同類型比較,直接進行“值”比較,兩者結果一樣 2、對于Array,Object等高級類型,==和===是沒有區(qū)別的

3、基礎類型與高級類型,==和===是有區(qū)別的 對于==,將高級轉化為基礎類型,進行“值”比較,因為類型不同,===結果為false

25.介紹下原型鏈(解決的是繼承問題嗎)

答: JavaScript原型: 每個對象都會在其內部初始化一個屬性,就是prototype(原型)。 原型鏈:

當我們訪問一個對象的屬性時,如果這個對象內部不存在這個屬性,那么他就會去prototype里找這個屬性,這個prototype又會有自己的prototype,于是就這樣一直找下去,也就是我們平時所說的原型鏈的概念。

特點:

JavaScript對象是通過引用來傳遞的,我們創(chuàng)建的每個新對象實體中并沒有一份屬于自己的原型副本。當我們修改原型時,與之相關的對象也會繼承這一改變。

26.JS里垃圾回收機制是什么,常用的是哪種,怎么處理的?

答:

JS的垃圾回收機制是為了以防內存泄漏,內存泄漏的含義就是當已經不需要某塊內存時這塊內存還存在著,垃圾回收機制就是間歇的不定期的尋找到不再使用的變量,并釋放掉它們所指向的內存。

JS中最常見的垃圾回收方式是標記清除。

工作原理:是當變量進入環(huán)境時,將這個變量標記為“進入環(huán)境”。當變量離開環(huán)境時,則將其標記為“離開環(huán)境”。標記“離開環(huán)境”的就回收內存。

工作流程:

垃圾回收器,在運行的時候會給存儲在內存中的所有變量都加上標記。

去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記。

再被加上標記的會被視為準備刪除的變量。

垃圾回收器完成內存清除工作,銷毀那些帶標記的值并回收他們所占用的內存空間。

27.Promise和setTimeout的區(qū)別?

答:

回顧JavaScript事件循環(huán)并發(fā)模型,我們了解了setTimeout和Promise調用的都是異步任務,這一點是它們共同之處,也即都是通過任務隊列進行管理/調度。那么它們有什么區(qū)別嗎?

任務隊列

前文已經介紹了任務隊列的基礎內容和機制,可選擇查看,本文對任務隊列進行拓展介紹。JavaScript通過任務隊列管理所有異步任務,而任務隊列還可以細分為MacroTask

Queue和MicoTask Queue兩類。 MacroTask Queue MacroTask

Queue(宏任務隊列)主要包括setTimeout,setInterval, setImmediate,

requestAnimationFrame, NodeJS中的`I/O等。 MicroTask Queue MicroTask

Queue(微任務隊列)主要包括兩類: 獨立回調microTask:如Promise,其成功/失敗回調函數相互獨立;

復合回調microTask:如 Object.observe, MutationObserver 和NodeJs中的

process.nextTick ,不同狀態(tài)回調在同一函數體; MacroTask和MicroTask

JavaScript將異步任務分為MacroTask和MicroTask,那么它們區(qū)別何在呢? 依次執(zhí)行同步代碼直至執(zhí)行完畢;

檢查MacroTask 隊列,若有觸發(fā)的異步任務,則取第一個并調用其事件處理函數,然后跳至第三步,若沒有需處理的異步任務,則直接跳至第三步;

檢查MicroTask隊列,然后執(zhí)行所有已觸發(fā)的異步任務,依次執(zhí)行事件處理函數,直至執(zhí)行完畢,然后跳至第二步,若沒有需處理的異步任務中,則直接返回第二步,依次執(zhí)行后續(xù)步驟;

最后返回第二步,繼續(xù)檢查MacroTask隊列,依次執(zhí)行后續(xù)步驟; 如此往復,若所有異步任務處理完成,則結束;

28.介紹下廣度優(yōu)先遍歷(BFS)和深度優(yōu)先遍歷(DFS)?

答:

1.廣度優(yōu)先遍歷 英文縮寫為BFS即Breadth FirstSearch。其過程檢驗來說是對每一層節(jié)點依次訪問,訪問完一層進入下一層,而且每個節(jié)點只能訪問一次。對于上面的例子來說,廣度優(yōu)先遍歷的

結果是:A,B,C,D,E,F,G,H,I(假設每層節(jié)點從左到右訪問)。 先往隊列中插入左節(jié)點,再插右節(jié)點,這樣出隊就是先左節(jié)點后右節(jié)點了。

廣度優(yōu)先遍歷樹,需要用到隊列(Queue)來存儲節(jié)點對象,隊列的特點就是先進先出。例如,上面這顆樹的訪問如下:

首先將A節(jié)點插入隊列中,隊列中有元素(A);

將A節(jié)點彈出,同時將A節(jié)點的左、右節(jié)點依次插入隊列,B在隊首,C在隊尾,(B,C),此時得到A節(jié)點;

繼續(xù)彈出隊首元素,即彈出B,并將B的左、右節(jié)點插入隊列,C在隊首,E在隊尾(C,D,E),此時得到B節(jié)點;

繼續(xù)彈出,即彈出C,并將C節(jié)點的左、中、右節(jié)點依次插入隊列,(D,E,F,G,H),此時得到C節(jié)點;

將D彈出,此時D沒有子節(jié)點,隊列中元素為(E,F,G,H),得到D節(jié)點; 。。。以此類推。。

2.深度優(yōu)先遍歷 英文縮寫為DFS即Depth First Search.其過程簡要來說是對每一個可能的分支路徑深入到不能再深入為止,而且每個節(jié)點只能訪問一次。對于上面的例子來說深度優(yōu)先遍歷的結果就是:A,B,D,E,I,C,F,G,H.(假設先走子節(jié)點的的左側)。

深度優(yōu)先遍歷各個節(jié)點,需要使用到棧(Stack)這種數據結構。stack的特點是是先進后出。整個遍歷過程如下:

先往棧中壓入右節(jié)點,再壓左節(jié)點,這樣出棧就是先左節(jié)點后右節(jié)點了。 首先將A節(jié)點壓入棧中,stack(A);

將A節(jié)點彈出,同時將A的子節(jié)點C,B壓入棧中,此時B在棧的頂部,stack(B,C);

將B節(jié)點彈出,同時將B的子節(jié)點E,D壓入棧中,此時D在棧的頂部,stack(D,E,C);

將D節(jié)點彈出,沒有子節(jié)點壓入,此時E在棧的頂部,stack(E,C); 將E節(jié)點彈出,同時將E的子節(jié)點I壓入,stack(I,C);

…依次往下,最終遍歷完成。 代碼:也是以二叉樹為例。

29.for in和for of的區(qū)別

答:

1.推薦在循環(huán)對象屬性的時候,使用for...in,在遍歷數組的時候的時候使用for...of

2.for...in循環(huán)出的是key,for...of循環(huán)出的是value

3.注意,for...of是ES6新引入的特性。修復了ES5引入的for...in的不足

4.for...of不能循環(huán)普通的對象,需要通過和Object.keys()搭配使用

30.typeof和instanceof 區(qū)別?

答: 在javascript中,判斷一個變量的類型可以用typeof   (1)

數字類型、typeof返回的值是number。比如說:typeof(1),返回值是number   (2)

字符串類型,typeof返回的值是string。比如typeof(“123”返回值時string)   (3)

布爾類型,typeof返回的值是boolean。比如typeof(true)返回值時boolean   (4)

對象、數組、null返回的值是object。比如typeof(window),typeof(document),typeof(null)返回的值都是object

(5) 函數類型,返回的值是function。比如:typeof(eval),typeof(Date)返回的值都是function。

(6)

不存在的變量、函數或者undefined,將返回undefined。比如:typeof(abc)、typeof(undefined)都返回undefined

在javascript中,instanceof用于判斷某個對象是否被另一個函數構造。

使用typeof運算符時采用引用類型存儲值會出現(xiàn)一個問題,無論引用的是什么類型的對象,它都返回”object”。ECMAScript引入了另一個Java運算符instanceof來解決這個問題。Instanceof運算符與typeof運算符相似,用于識別正在處理的對象的類型。與typeof方法不同的是,instanceof方法要求開發(fā)者明確地確認對象為某特定類型

31.常見的繼承有幾種方法?

答:

1.原型鏈繼承

2.構造函數繼承(經典繼承)

3.組合方式繼承(構造函數 + 原型鏈)

4.es6方法繼承

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374