每天10道題,100天后,搞定所有前端面試的高頻知識(shí)點(diǎn),加油?。。?,在看文章的同時(shí),希望不要直接看答案,先思考一下自己會(huì)不會(huì),如果會(huì),自己的答案是什么?想過(guò)之后再與答案比對(duì),是不是會(huì)更好一點(diǎn),當(dāng)然如果你有比我更好的答案,歡迎評(píng)論區(qū)留言,一起探討技術(shù) 之美。
1)我們要知道在全局的時(shí)候去得到這個(gè)this的話,this都會(huì)指向windows,因?yàn)槲覀冊(cè)谌值那闆r下使用的東西都會(huì)被掛載到window上。
<script> console.log(this) // 指向window function a(){ console.log(this) } a() // 相當(dāng)于 window.a(),指向的依舊是 window</script>2)我要知道this的指向是會(huì)指向上一個(gè)調(diào)用者的,代碼如下:
(資料圖片僅供參考)
看完了代碼,我們知道雖然本質(zhì)上是由于a才調(diào)用了d函數(shù),但是中間還是有一層是c調(diào)用了d函數(shù),所以this指向上一級(jí)會(huì)有一個(gè)就近原則的,這點(diǎn)很重要!?。?/p><script> var a = { b:10, c:{ b:12, d:function(){ console.log(this) } } } a.c.d() // {b: 12, d: ?}</script>
3)我們要知道箭頭函數(shù)是沒有作用域的,也就是說(shuō)是沒有自己的this,它的this永遠(yuǎn)向的是上一級(jí)的this,下面給出一道某大廠的面試題,大家可以猜一下最后的打印結(jié)果是什么?
假設(shè)你已經(jīng)仔細(xì)的看完了這道面試題,相信你心中已經(jīng)有了答案是66了,為什么呢?,要知道箭頭函數(shù)是沒有自己的this的,所以需要其去上一級(jí)去尋找this,而上一級(jí)處于全局作用域,所以打印的便是全局已經(jīng)掛載的id數(shù)66。
<script> var id = 66 function a(){ setTimeout(()=>{ console.log(this.id) },500) } a({id:22}) // 猜猜結(jié)果是什么?</script>那我們如何改變this的指向,去控制this指向我們想要的結(jié)果呢?給出如下三種方法:
<script> var id = 66 function a(){ setTimeout(()=>{ console.log(this.id || this) },500) } // call => {} 改變之后并執(zhí)行一次 a.call({id:22}) // 打印22 // apply => [] 改變之后并執(zhí)行一次 a.apply([12]) // 打印 [12] // bind() 不調(diào)用,只改變this指向 a.bind(a(id=32)) // 32</script>我:呃~,好的,總結(jié)如下:
call apply bind三個(gè)方法都可以用來(lái)改變函數(shù)的this指向,具體區(qū)別如下:
1)fn.call (newThis,params) call函數(shù)的第一個(gè)參數(shù)是this的新指向,后面依次傳入函數(shù)fn要用到的參數(shù)。會(huì)立即執(zhí)行fn函數(shù)。
2)fn.apply (newThis,paramsArr) apply函數(shù)的第一個(gè)參數(shù)是this的新指向,第二個(gè)參數(shù)是fn要用到的參數(shù)數(shù)組,會(huì)立即執(zhí)行fn函數(shù)。
3)fn.bind (newThis,params) bind函數(shù)的第一個(gè)參數(shù)是this的新指向,后面的參數(shù)可以直接傳遞,也可以按數(shù)組的形式傳入。 不會(huì)立即執(zhí)行fn函數(shù),且只能改變一次fn函數(shù)的指向,后續(xù)再用bind更改無(wú)效。返回的是已經(jīng)更改this指向的新fn
我:呃~,好的,事件委托就是利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。說(shuō)白了就是將還沒有出現(xiàn)的事件,掛載到已經(jīng)出現(xiàn)的事件上。整出代碼如下:
<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">點(diǎn)我添加一個(gè)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提供的一個(gè)構(gòu)造函數(shù),可以使用Promise構(gòu)造函數(shù)new一個(gè)實(shí)例,Promise構(gòu)造函數(shù)接收一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)有兩個(gè)參數(shù),分別是兩個(gè)函數(shù) resolve和reject,resolve將Promise的狀態(tài)由等待變?yōu)槌晒?,將異步操作的結(jié)果作為參數(shù)傳遞過(guò)去;reject則將狀態(tài)由等待轉(zhuǎn)變?yōu)槭?,在異步操作失敗時(shí)調(diào)用,將異步操作報(bào)出的錯(cuò)誤作為參數(shù)傳遞過(guò)去。實(shí)例創(chuàng)建完成后,可以使用then方法分別指定成功或失敗的回調(diào)函數(shù),也可以使用catch捕獲失敗,then和catch最終返回的也是一個(gè)Promise,所以可以鏈?zhǔn)秸{(diào)用。
Promise的作用:
Promise是異步微任務(wù),解決了異步多層嵌套回調(diào)的問(wèn)題,讓代碼的可讀性更高,更容易維護(hù) Promise使用
Promise的特點(diǎn):
1)對(duì)象的狀態(tài)不受外界影響
2)一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果
3)resolve 方法的參數(shù)是then中回調(diào)函數(shù)的參數(shù),reject 方法中的參數(shù)是catch中的參數(shù)
4)then 方法和 catch方法 只要不報(bào)錯(cuò),返回的都是一個(gè)fullfilled狀態(tài)的promise
應(yīng)用場(chǎng)景:
解決地獄回調(diào)問(wèn)題
具體使用方法,參考我之前的文章:一文搞懂JS中的Promise
我:呃,好的,總結(jié)內(nèi)容如下:
什么是跨域:
當(dāng)前頁(yè)面中的某個(gè)接口請(qǐng)求的地址和當(dāng)前頁(yè)面的地址如果協(xié)議、域名、端口其中有一項(xiàng)不同,就說(shuō)該接口跨域了。 跨域限制的原因:
瀏覽器為了保證網(wǎng)頁(yè)的安全,出的同源協(xié)議策略。
跨域解決方案:
cors:
目前最常用的一種解決辦法,通過(guò)設(shè)置后端允許跨域?qū)崿F(xiàn)。 res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST");
node中間件、nginx反向代理:
跨域限制的時(shí)候?yàn)g覽器不能跨域訪問(wèn)服務(wù)器,node中間件和nginx反向代理,都是讓請(qǐng)求發(fā)給代理服務(wù)器,靜態(tài)頁(yè)面面和代理服務(wù)器是同源的,然后代理服務(wù)器再向后端服務(wù)器發(fā)請(qǐng)求,服務(wù)器和服務(wù)器之間不存在同源限制。JSONP:
利用的原理是script標(biāo)簽可以跨域請(qǐng)求資源,將回調(diào)函數(shù)作為參數(shù)拼接在url中。后端收到請(qǐng)求,調(diào)用該回調(diào)函數(shù),并將數(shù)據(jù)作為參數(shù)返回去,注意設(shè)置響應(yīng)頭返回文檔類型,應(yīng)該設(shè)置成javascript。
我:呃,好的,JavaScript有4種方法判斷變量的類型,總結(jié)如下:
typeof:
常用于判斷基本數(shù)據(jù)類型,對(duì)于引用數(shù)據(jù)類型除了function返回’function‘,其余全部返回’object"。
instanceof:
主要用于區(qū)分引用數(shù)據(jù)類型,檢測(cè)方法是檢測(cè)的類型在當(dāng)前實(shí)例的原型鏈上,用其檢測(cè)出來(lái)的結(jié)果都是true
Object.prototype.toString.call()(對(duì)象原型鏈判斷方法):
適用于所有類型的判斷檢測(cè),檢測(cè)方法是Object.prototype.toString.call(數(shù)據(jù)) 返回的是該數(shù)據(jù)類型的字符串。
constructor(用于引用數(shù)據(jù)類型):
用于檢測(cè)引用數(shù)據(jù)類型,檢測(cè)方法是獲取實(shí)例的構(gòu)造函數(shù)判斷和某個(gè)類是否相同,如果相同就說(shuō)明該數(shù)據(jù)是符合那個(gè)數(shù)據(jù)類型的,這種方法不會(huì)把原型鏈上的其他類也加入進(jìn)來(lái),避免了原型鏈的干擾。
我:呃~,好的,所有異步任務(wù)都是在同步任務(wù)執(zhí)行結(jié)束之后,從任務(wù)隊(duì)列中依次取出執(zhí)行。常見的實(shí)現(xiàn)異步的方式如下:
回調(diào)函數(shù)、事件監(jiān)聽、setTimeout(定時(shí)器)、Promise、async/await,generator生成器
我:呃~,數(shù)組去重的方法有很多,舉幾個(gè)例子并簡(jiǎn)單的加以說(shuō)明,如下:
利用對(duì)象屬性key排除重復(fù)項(xiàng):
遍歷數(shù)組,每次判斷對(duì)象中是否存在該屬性,不存在就存儲(chǔ)在新數(shù)組中,并且把數(shù)組元素作為key,設(shè)置一個(gè)值,存儲(chǔ)在對(duì)象中,最后返回新數(shù)組。
利用Set類型數(shù)據(jù)無(wú)重復(fù)項(xiàng):
new 一個(gè) Set,參數(shù)為需要去重的數(shù)組,Set 會(huì)自動(dòng)刪除重復(fù)的元素,再將 Set 轉(zhuǎn)為數(shù)組返回。
filter+indexof 去重:
利用 Array 自帶的 filter 方法,返回 arr.indexOf(num) 等于 index 的num。
reduce +includes去重:
利用reduce遍歷和傳入一個(gè)空數(shù)組作為去重后的新數(shù)組,然后內(nèi)部判斷新數(shù)組中是否存在當(dāng)前遍歷的元素,不存在就插入到新數(shù)組中。
我:呃~,好的,箭頭函數(shù)相當(dāng)于匿名函數(shù),簡(jiǎn)化了函數(shù)定義。箭頭函數(shù)有兩種寫法,當(dāng)函數(shù)體是單條語(yǔ)句的時(shí)候可以省略{}和return。另一種是包含多條語(yǔ)句,不可以省略{}和return。 箭頭函數(shù)最大的特點(diǎn)就是沒有this,所以this是從外部獲取,就是繼承外部的執(zhí)行上下文中的this,由于沒有this關(guān)鍵字所以箭頭函數(shù)也不能作為構(gòu)造函數(shù)。
箭頭函數(shù)比普通函數(shù)的定義寫法更加簡(jiǎn)潔明了和快捷。但是兩者又有區(qū)別:箭頭函數(shù)沒有原型prototype和super,所以無(wú)法創(chuàng)建this,其this是通過(guò)繼承外部函數(shù)環(huán)境中的變量獲取的,所以call、bind、apply都無(wú)法改變其this的指向;在找不到最外層的普通函數(shù)時(shí),其this一般指向window;箭頭函數(shù)不能使用new;箭頭函數(shù)沒有arguments;也不能作為generator函數(shù),不能使用yield命令;箭頭函數(shù)不能用于對(duì)象域和回調(diào)函數(shù)動(dòng)態(tài)this中,一般用在內(nèi)部沒有this引用。
我:呃~,好的,變量提升是指JS的變量和函數(shù)聲明會(huì)在代碼編譯期,提升到代碼的最前面。 變量提升成立的前提是使用Var關(guān)鍵字進(jìn)行聲明的變量,并且變量提升的時(shí)候只有聲明被提升,賦值并不會(huì)被提升,同時(shí)函數(shù)的聲明提升會(huì)比變量的提升優(yōu)先。 變量提升的結(jié)果,可以在變量初始化之前訪問(wèn)該變量,返回的是undefined。在函數(shù)聲明前可以調(diào)用該函數(shù)。
使用let和const聲明的變量是創(chuàng)建提升,形成暫時(shí)性死區(qū),在初始化之前訪問(wèn)let和const創(chuàng)建的變量會(huì)報(bào)錯(cuò)。
【推薦學(xué)習(xí):javascript高級(jí)教程】
以上就是看看這些前端面試題,帶你搞定高頻知識(shí)點(diǎn)(七)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
關(guān)鍵詞: javascript