每天10題,100天后,搞定所有前端面試的高頻知識點,加油! ! ! ,在看文章的同時,希望不要直接看答案,先思考一下自己會不會,如果會,自己的答案是什麼?想過之後再與答案比對,是不是會更好一點,當然如果你有比我更好的答案,歡迎評論區留言,一起探討技術 之美。
我:呃~,我們知道this中 #有個準則是誰呼叫就指向誰,這句話潛移默化的會導致我們出現一些誤區,現將可能會出錯的情況總結如下,並付出代碼:
1)我們要知道在全域的時候去得到這個this的話,this都會指向windows,因為我們在全域的情況下所使用的東西都會被掛載到window上。
<script> console.log(this) // 指向window function a(){ console.log(this) } a() // 相当于 window.a(),指向的依旧是 window </script>
2)我要知道this的指向是會指向上一個呼叫者的,程式碼如下:
看完了程式碼,我們知道雖然本質上是由於a才呼叫了d函數,但中間還是有一層是c呼叫了d函數,所以this指向上一級會有一個就近原則的,這點很重要! ! !
<script> var a = { b:10, c:{ b:12, d:function(){ console.log(this) } } } a.c.d() // {b: 12, d: ƒ} </script>
3)我們要知道箭頭函數是沒有作用域的,也就是說是沒有自己的this,它的this永遠向的是上一級的this,下面給出一道某大工廠的面試題,大家可以猜一下最後的列印結果是什麼?
假設你已經仔細的看完了這道面試題,相信你心中已經有了答案是66了,為什麼呢? ,要知道箭頭函數是沒有自己的this的,所以需要其去上一級去尋找this,而上一級處於全局作用域,所以打印的便是全局已經掛載的id數66。
<script> var id = 66 function a(){ setTimeout(()=>{ console.log(this.id) },500) } a({id:22}) // 猜猜结果是什么? </script>
那我們如何改變this的指向,去控制this指向我們想要的結果呢?給出以下三種方法:
<script> var id = 66 function a(){ setTimeout(()=>{ console.log(this.id || this) },500) } // call => {} 改变之后并执行一次 a.call({id:22}) // 打印22 // apply => [] 改变之后并执行一次 a.apply([12]) // 打印 [12] // bind() 不调用,只改变this指向 a.bind(a(id=32)) // 32 </script>
我:呃~,好的,總結如下:
call apply bind三個方法都可以用來改變函數的this指向,具體區別如下:
1)fn.call (newThis,params) call函數的第一個參數是this的新指向,後面依序傳入函數fn要用到的參數。會立即執行fn函數。
2)fn.apply (newThis,paramsArr) apply函數的第一個參數是this的新指向,第二個參數是fn要用到的參數數組,會立即執行fn函數。
3)fn.bind (newThis,params) bind函數的第一個參數是this的新指向,後面的參數可以直接傳遞,也可以以陣列的形式傳入。 不會立即執行fn函數,只能改變一次fn函數的指向,後續再用bind更改無效。返回的是已經更改this指向的新fn
我:呃~ ,好的,事件委託就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。說穿了就是將還沒有出現的事件,掛載到已經出現的事件上。整出程式碼如下:
<body> <ul id="ul"> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <button id="btn">点我添加一个li</button> <script> // 事件委托 let ul = document.getElementById("ul") ul.addEventListener('click',(event)=>{ console.log(event) event = event || window.event let target = event.target if(target.nodeName == 'LI'){ alert(target.innerHTML) } }) let btn = document.getElementById('btn') btn.addEventListener('click',()=>{ let li = document.createElement('li') li.textContent = ul.children.length ul.appendChild(li) }) </script> </body>#
我:呃~,好的,Promise是ES6提供的建構函數,可以使用Promise建構函式new一個實例,Promise建構函式接收一個函數當參數,這個函數有兩個參數,分別是兩個函數resolve和reject,resolve將Promise的狀態由等待變為成功,將非同步操作的結果作為參數傳遞過去;reject則將狀態由等待轉變為失敗,在非同步操作失敗時調用,將非同步操作報出的錯誤會作為參數傳遞過去。實例建立完成後,可以使用then方法分別指定成功或失敗的回呼函數,也可以使用catch#擷取失敗,then和catch最終回傳的也是一個Promise,所以可以鍊式呼叫。
Promise的作用:
Promise是非同步微任務,解決了非同步多層嵌套回呼的問題,讓程式碼的可讀性更高,更容易維護Promise使用
Promise的特徵:
1)物件的狀態不受外界影響
2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果
3)resolve 方法的參數是then中回呼函數的參數,reject 方法中的參數是catch中的參數
4)then 方法和catch方法只要不報錯,回傳的都是一個fullfilled狀態的promise
##應用場景:
解決地獄回呼問題具體使用方法,參考我之前的文章:
我:呃,好的,總結內容如下:什麼是跨域:
目前頁面中的某個介面請求的位址和目前頁面的位址如果協定、網域名稱、連接埠其中有一項不同,就說該介面跨域了。跨網域限制的原因:
瀏覽器為了確保網頁的安全,所出的同源協定策略。跨域解決方案:
#cors:
目前最常用的一種解決辦法,透過設定後端允許跨域實現。res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST");node中間件、nginx反向代理:
跨網域限制的時候瀏覽器不能跨網域存取伺服器,node中間件和nginx反向代理,都是讓請求發給代理伺服器,靜態頁面面和代理伺服器是同源的,然後代理伺服器再向後端伺服器發送請求,伺服器和伺服器之間不存在同源限制。利用的原理是script標籤可以跨域請求資源,將回呼函數當作參數拼接在url中。後端收到請求,呼叫該回呼函數,並將資料作為參數返回去,注意設定回應頭返回文檔類型,應該設定成javascript。
JSONP:
我:呃,好的,JavaScript有4種方法判斷變數的類型,總結如下:typeof:
常用於判斷基本資料型,對於引用資料型別除了function回傳'function',其餘全部回傳'object'。instanceof:
主要用於區分引用資料類型,偵測方法是偵測的類型在目前實例的原型鏈上,用其檢測出來的結果都是trueObject.prototype.toString.call()(物件原型鏈判斷方法):
適用於所有類型的判斷偵測,偵測方法是Object .prototype.toString.call(資料) 傳回的是該資料型別的字串。
constructor(用於引用資料類型):
用於偵測引用資料類型,偵測方法是取得實例的建構子判斷和某個類別是否相同,如果相同就說明該資料是符合那個資料類型的,這種方法不會把原型鏈上的其他類別也加入進來,避免了原型鏈的干擾。
我:呃~,好的,所有非同步任務都是在同步任務執行結束之後,從任務佇列中依序取出執行。常見的實作非同步的方式如下:
回呼函數、事件監聽、setTimeout(計時器)、Promise、async/await,generator產生器
我:呃~,陣列去重的方法有很多,舉幾個例子並簡單的加以說明,如下:
利用物件屬性key排除重複項:
遍歷數組,每次判斷物件中是否存在該屬性,不存在就儲存在新數組中,並且把數組元素當作key,設定一個值,儲存在物件中,最後傳回新數組。
利用Set類型資料無重複項:
#new 一個Set,參數為需要去重的數組,Set 會自動刪除重複的元素,再將Set 轉為陣列返回。
filter indexof 去重:
使用 Array 自帶的 filter 方法,回傳 arr.indexOf(num) 等於 index 的num。
reduce includes去重:
#利用reduce遍歷和傳入一個空數組作為去重後的新數組,然後內部判斷新數組中是否存在目前遍歷的元素,不存在就插入到新數組中。
我:呃~,好的,箭頭函數相當於匿名函數,簡化了函數定義。箭頭函數有兩種寫法,當函數體是單一語句的時候可以省略{}和return。另一種是包含多個語句,不可以省略{}和return。箭頭函數最大的特點就是沒有this,所以this是從外部獲取,就是繼承外部的執行上下文中的this,由於沒有this關鍵字所以箭頭函數也不能作為建構函數。
箭頭函數比一般函數的定義寫法更簡潔明了和快速。但兩者又有區別:箭頭函數沒有原型prototype和super,所以無法創建this,其this是透過繼承外部函數環境中的變數取得的,所以call、bind、apply都無法改變其this的指向;在找不到最外層的普通函數時,其this一般指向window;箭頭函數不能使用new;箭頭函數沒有arguments;也不能作為generator函數,不能使用yield命令;箭頭函數不能用於對象域和回調函數動態this中,一般用在內部沒有this引用。
我:呃~,好的,變數提升是指JS的變數和函數宣告會在程式碼編譯期,提升到程式碼的最前面。變數提升成立的前提是使用Var關鍵字進行宣告的變量,且變數提升的時候只有宣告被提升,賦值不會被提升,同時函數的宣告提升會比變數的提升優先。變數提升的結果,可以在變數初始化之前存取該變量,傳回的是undefined。在函數宣告前可以呼叫該函數。
使用let和const宣告的變數是建立提升,形成暫時性死區,在初始化之前存取let和const所建立的變數會報錯。
【推薦學習:javascript進階教學】
以上是看看這些前端面試題,帶你搞定高頻知識點(七)的詳細內容。更多資訊請關注PHP中文網其他相關文章!