自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

2022 Web 前端面試題及答案之JavaScript 篇

開發(fā) 前端
給大家分享一篇面試相關(guān)文章,希望大家在 2022 年,摸魚時(shí)間越來越多,薪資越漲越快!

給大家分享一篇面試相關(guān)文章,希望大家在 2022 年,摸魚時(shí)間越來越多,薪資越漲越快!

1、事件循環(huán)機(jī)制

阿里面試題1:

  1. <script type="text/javascript"
  2.  var p =new Promise(resolve=>{ 
  3.   console.log(4) 
  4.   resolve(5) 
  5.  }) 
  6.  function f1(){ 
  7.   console.log(1) 
  8.  } 
  9.  function f2(){ 
  10.   setTimeout(()=>{ 
  11.    console.log(2) 
  12.   },0) 
  13.   f1() 
  14.   console.log(3) 
  15.   p.then(res=>{ 
  16.    console.log(res) 
  17.   }) 
  18.  } 
  19.  f2() 
  20. </script> 
  21. // 運(yùn)行結(jié)果 4 1 3 5 2 
  22. // 如果已經(jīng)了解事件運(yùn)行機(jī)制,就可以跳過該問題了 

 事件循環(huán)機(jī)制,event-loop 。包含三部分:調(diào)用棧、消息隊(duì)列、微任務(wù)隊(duì)列。

事件循環(huán)開始的時(shí)候,會(huì)從全局一行一行的執(zhí)行代碼,遇到函數(shù)調(diào)用的時(shí)候,就會(huì)壓入調(diào)用棧中,當(dāng)函數(shù)執(zhí)行完成之后,彈出調(diào)用棧。

  1. // 如:代碼會(huì)一行一行執(zhí)行,函數(shù)全部調(diào)用完成之后清空調(diào)用棧 
  2. function f1(){ 
  3.  console.log(1) 
  4. function f2(){ 
  5.  f1() 
  6.  console.log(2) 
  7. f2() 
  8. // 執(zhí)行結(jié)果 1 2 

 如果遇到 fetch、setInterval、setTimeout 異步操作時(shí),函數(shù)調(diào)用壓入調(diào)用棧時(shí),異步執(zhí)行內(nèi)容會(huì)被加入消息隊(duì)列中,消息隊(duì)列中的內(nèi)容會(huì)等到調(diào)用棧清空之后才會(huì)執(zhí)行。

  1. // 如: 
  2. function f1(){ 
  3.  console.log(1) 
  4. function f2(){ 
  5.  setTimeout(()=>{ 
  6.   console.log(2) 
  7.  },0) 
  8.  f1() 
  9.  console.log(3) 
  10. f2() 
  11. // 執(zhí)行結(jié)果 :1 3 2 

 遇到 promise、async、await 異步操作時(shí),執(zhí)行內(nèi)容會(huì)被加入微任務(wù)隊(duì)列中,會(huì)在調(diào)用棧清空之后立即執(zhí)行。

調(diào)用棧加入的微任務(wù)隊(duì)列會(huì)立即執(zhí)行。

  1. 如 
  2. let p =new Promise(resolve=>{ 
  3.  console.log('立即執(zhí)行'
  4.  resolve(1) //在 then 調(diào)用中執(zhí)行 
  5. }) 

 微任務(wù)隊(duì)列中內(nèi)容優(yōu)先執(zhí)行,所以比消息隊(duì)列中的內(nèi)容執(zhí)行得早。

了解這些知識(shí)后,再試一下最前面的那道面試題,應(yīng)該就沒什么問題了。

2、你對(duì)作用域的認(rèn)識(shí)有多少?

阿里面試題2:

  1. <script type="text/javascript"
  2.  function fn(a,c){ 
  3.   console.log(a) 
  4.   var a = 12 
  5.   console.log(a) 
  6.   console.log(c) 
  7.   function a(){ } 
  8.   if(false){ 
  9.    var d = 34 
  10.   } 
  11.   console.log(d) 
  12.   console.log(b) 
  13.   var b = function(){} 
  14.   console.log(b) 
  15.   function c(){} 
  16.   console.log(c) 
  17.  } 
  18.  fn(1,2) 
  19. </script> 
  20. // 運(yùn)行結(jié)果: 
  21. /* 
  22. function a(){} 
  23. 12 
  24. function c(){} 
  25. undefined 
  26. undefined 
  27. function (){} 
  28. function c(){} 
  29. */ 

 作用域通俗地講,就是指一個(gè)變量的作用范圍。下面分別介紹下全局作用域和函數(shù)作用域的概念。

全局作用域

  • 頁面打開時(shí)被創(chuàng)建,頁面關(guān)閉時(shí)被銷毀。
  • 編寫在 script 標(biāo)簽下的變量和函數(shù),作用域?yàn)槿?,頁面的任意位置都可以訪問
  • 有全局對(duì)象 window ,代表瀏覽器窗口,全局作用下的變量和函數(shù)作為 window 的屬性和方法

函數(shù)作用域(局部)

  • 函數(shù)是被調(diào)用時(shí)創(chuàng)建的,執(zhí)行完畢之后銷毀。
  • 函數(shù)每調(diào)用一次,變量和函數(shù)就會(huì)重新創(chuàng)建一次,它們之間是相互獨(dú)立的
  • 在函數(shù)作用域內(nèi)可以訪問到全局變量或函數(shù),但是在函數(shù)外無法訪問函數(shù)作用域內(nèi)的變量
  • 函數(shù)作用域內(nèi)訪問變量,會(huì)在自身作用域內(nèi)尋找,若沒有則會(huì)向上一級(jí)作用域內(nèi)查找,一直到全局作用域。

講這些概念看完,發(fā)現(xiàn)還不會(huì)做上邊的面試題,接下來就學(xué)習(xí)學(xué)習(xí)作用域的預(yù)編譯,看看函數(shù)執(zhí)行的時(shí)候都干了些啥?

函數(shù)在被調(diào)用的時(shí)候會(huì)先進(jìn)行預(yù)編譯:

全局作用域預(yù)編譯:

  • 創(chuàng)建上下文 GO 對(duì)象。
  • 找變量聲明,將變量名作為 GO 對(duì)象的屬性名,值為 undefined
  • 找函數(shù)式聲明,將值賦予函數(shù)體

函數(shù)作用域預(yù)編譯:

  • 創(chuàng)建上下文 AO 對(duì)象
  • 將形參和實(shí)參作為 AO 對(duì)象的屬性,賦值為 undefined
  • 實(shí)參和形參相統(tǒng)一
  • 在函數(shù)體內(nèi)找函數(shù)聲明,將值賦予函數(shù)體。

了解預(yù)編譯過程之后,我們將上面的面試題進(jìn)行解析,分析下運(yùn)行結(jié)果是怎么來的?

fn 函數(shù)調(diào)用的時(shí)候,先進(jìn)行預(yù)編譯,

第一階段:生成一個(gè) AO 對(duì)象

第二階段:找到形參和實(shí)參,作為 AO 對(duì)象的屬性名,值為 udefined 。

  1. AO{ 
  2. a : undefined, 
  3. b : undefined, 
  4. c : undefined, 
  5. d : undefined 

 第三階段:實(shí)參和形參相統(tǒng)一,之后,AO對(duì)象改變?yōu)椋?/p>

  1. AO{ 
  2. a : 1, 
  3. b : undefined, 
  4. c : 2, 
  5. d : undefined 

 第四階段:找到函數(shù)聲明,將值賦給變量,AO改變?yōu)椋?/p>

  1. AO{ 
  2. a : function a(){ } , 
  3. b : undefined, 
  4. c : function c(){ }, 
  5. d : undefined 

 這下結(jié)合函數(shù)的預(yù)編譯過程以及函數(shù)作用域概念,再嘗試一下面試題,簡單了嗎?

3、為什么會(huì)有閉包?它解決了什么問題?

實(shí)例3:

  1. var liArr = document.getElementsByTagName('li'
  2. for(var i=0;i<liArr.length;i++){ 
  3.  liArr[i].onclick = function(){ 
  4.   console.log(liArr[i]) 
  5.  } 

 這是一個(gè)非常常見的實(shí)際應(yīng)用,我們是想要點(diǎn)擊元素然后操作對(duì)應(yīng)的元素,但是點(diǎn)擊之后發(fā)現(xiàn)打印出來的是 undefined 。我們應(yīng)該能想到 i 變成了 liArr.length ,所以找不到對(duì)應(yīng)元素,這個(gè)問題該如何解決呢?

說閉包時(shí),必須介紹作用域。

上面介紹全局作用域和函數(shù)作用域,js內(nèi)部變量的訪問是由內(nèi)向外的,內(nèi)部可以訪問到外部的變量,但是外部無法訪問函數(shù)內(nèi)的變量,如果我們在外部訪問函數(shù)內(nèi)的變量就需要使用閉包。

閉包就是函數(shù)嵌套函數(shù),通過函數(shù)內(nèi)的函數(shù)訪問變量的規(guī)則,實(shí)現(xiàn)外部訪問函數(shù)內(nèi)的變量。

閉包的特點(diǎn):

  • 函數(shù)嵌套函數(shù)。
  • 函數(shù)內(nèi)部可以引用函數(shù)外部的參數(shù)和變量。
  • 參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收。

那么上述實(shí)例該如何使用閉包解決該問題呢?

實(shí)例3:閉包解決問題

  1. var liArr = document.getElementsByTagName('li'
  2. for(var i=0;i<liArr.length;i++){ 
  3.  (function(i){ 
  4.   liArr[i].onclick = function(){ 
  5.    console.log('點(diǎn)擊元素',liArr[i]) 
  6.   } 
  7.  })(i)  

 閉包優(yōu)點(diǎn):

  • 保護(hù)變量安全,實(shí)現(xiàn)封裝,防止變量聲明沖突和全局污染。
  • 在內(nèi)存當(dāng)中維持一個(gè)變量,可以做緩存。
  • 匿名函數(shù)自執(zhí)行函數(shù)可以減少內(nèi)存消耗。

防抖和節(jié)流就是閉包的經(jīng)典應(yīng)用。

4、防抖和節(jié)流,你了解多少?

在實(shí)際應(yīng)用中,常見的就是窗口的 resize、輸入框搜索內(nèi)容、scroll 等操作,如果這些操作觸發(fā)頻率太高,就會(huì)加重瀏覽器的負(fù)擔(dān),同時(shí)用戶體驗(yàn)也較差。該如何優(yōu)化該操作呢?

防抖函數(shù)是什么呢?

當(dāng)持續(xù)觸發(fā)事件,一定時(shí)間內(nèi)沒有再觸發(fā)事件,事件處理函數(shù)才會(huì)執(zhí)行一次,如果在設(shè)定的時(shí)間到來之前又觸發(fā)了事件,就會(huì)重新計(jì)時(shí)。

實(shí)例4:我們想要制作一個(gè)輸入框搜索,計(jì)劃輸入完成后兩秒再執(zhí)行,打印出輸入的值。

  1. function debounce(val){ 
  2.  var timer 
  3.  clearTimeout(timer) 
  4.  timer = setTimeout(function(){ 
  5.   console.log(val) 
  6.  },2000) 
  7. var input = document.getElementById('input'
  8. input.addEventListener('keyup',function(e){ 
  9.  debounce(e.target.value) 
  10. }) 

 實(shí)際運(yùn)行結(jié)果:我們發(fā)現(xiàn)輸入之后,延時(shí)兩秒之后打印出結(jié)果。

2022 Web 前端面試題及答案 之 javaScript 篇

并非我們想要的結(jié)果,這是什么原因呢?

因?yàn)楹瘮?shù)每次重新調(diào)用的時(shí)候 timer 會(huì)重新創(chuàng)建,調(diào)用完成之后就會(huì)被銷毀,所以每次重新調(diào)用函數(shù)的時(shí)候,clearTimeout 內(nèi)的 timer 都是 undefined 。所以我們需要把 timer 始終保持在內(nèi)存當(dāng)中,所以就需要使用閉包。

使用閉包修改上述實(shí)例4:

  1. function debounce(delay){ 
  2.  var timer 
  3.  return function(val){ 
  4.   clearTimeout(timer) 
  5.   timer = setTimeout(function(){ 
  6.    console.log(val) 
  7.   },delay) 
  8.  } 
  9. var debounceFun = debounce(2000) 
  10. var input = document.getElementById('input'
  11. input.addEventListener('keyup',function(e){ 
  12.  debounceFun(e.target.value) 
  13. }) 

防抖函數(shù)常見的實(shí)際應(yīng)用:使用 echart 的時(shí)候,瀏覽器 resize 時(shí),需要重新繪制圖表大小,還有典型的輸入框搜索應(yīng)用。

節(jié)流函數(shù)是什么?

當(dāng)持續(xù)觸發(fā)事件的時(shí)候,保證一段時(shí)間內(nèi)只調(diào)用一次事件處理函數(shù),一段時(shí)間內(nèi),只允許做一件事情。

實(shí)例5:滾動(dòng)條實(shí)現(xiàn)一段時(shí)間內(nèi)執(zhí)行一次處理,執(zhí)行回調(diào)。

  1. var throttle = function(func, delay) {             
  2.  var timer = null;             
  3.  return function() {                 
  4.   var context = this;                
  5.   var args = arguments;                 
  6.   if (!timer) {                     
  7.    timer = setTimeout(function() {                         
  8.     func.apply(context, args);                         
  9.      timer = null;                     
  10.     }, delay);                 
  11.    }             
  12.  }         
  13. }         
  14. function handle() {             
  15.  console.log('執(zhí)行回調(diào)');         
  16. }         
  17. window.addEventListener('scroll', throttle(handle, 1000));  

防抖和節(jié)流主要是用來限制觸發(fā)頻率較高的事件,再不影響效果的前提條件下,降低事件觸發(fā)頻率,減小瀏覽器或服務(wù)器的壓力,提升用戶體驗(yàn)效果。

5、數(shù)組去重有幾種方法?

這是一個(gè)非常常見的面試題,你知道幾種方式呢?

  1. var arr = [1,2,3,4,5,1,2,3,4] 
  2. function unique(arr){ 
  3.   //添加去重的方法的內(nèi)容 
  4. unique(arr) 

方法1: Set 方法

  1. return Array.from(new Set(arr)) 
  2.  
  3. // 或 
  4.  
  5. return [...new Set(arr)] 

 new Set 返回的數(shù)據(jù)不是數(shù)組,所以使用 Aray.from 方法將類數(shù)組轉(zhuǎn)為真正的數(shù)組,或把 ...new Set(arr) 放入數(shù)組中。

方法2:使用兩次循環(huán)

  1. for(var i=0,len=arr.length;i<len;i++){ 
  2.  for(var j=i+1,len=arr.length;j<len;j++){ 
  3.   if( arr[i]===arr[j] ){ 
  4.    arr.splice(i,1) 
  5.    j--; 
  6.    len-- 
  7.   } 
  8.  } 
  9. return arr 

方法3:indexOf 實(shí)現(xiàn)

arr.indexOf(item) 返回 item 元素在 arr 數(shù)組中第一次出現(xiàn)所在位置的下標(biāo)。

  1. let arr1 = [] 
  2. for(var i=0;i<arr.length;i++){ 
  3.  if( arr1.indexOf(arr[i]) === -1 ){ 
  4.   arr1.push(arr[i]) 
  5.  } 
  6. return arr1 

方法4:includes 實(shí)現(xiàn)

  1. let arr1 = [] 
  2. for(var i=0;i<arr.length;i++){ 
  3.  if( !arr1.includes(arr[i]) ){ 
  4.   arr1.push(arr[i]) 
  5.  } 
  6. return arr1 

方法5:filter 實(shí)現(xiàn)

array.indexOf(item,start) start 表示開始檢索的位置。

  1. return arr.filter(( item, index )=>{ 
  2.  return arr.indexOf( item, 0 ) == index 
  3. }) 

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-07-27 08:27:34

Call前端

2023-08-27 15:57:28

前端開發(fā)

2021-02-02 06:12:39

JavaScript 前端面試題

2022-05-08 19:36:35

Web前端時(shí)間復(fù)雜度

2019-02-21 14:12:26

前端面試題Vue

2023-05-19 08:21:40

MarginCSS

2022-02-09 07:40:42

JavaScript前端面試題

2012-06-28 14:35:49

Web

2012-06-26 11:09:07

Web

2009-02-16 13:03:43

華為面試

2024-02-26 15:35:44

2009-06-16 13:41:19

Hibernate面試Hibernate面試

2021-10-27 11:00:30

C++語言面試

2022-05-08 19:58:10

JSONPJavaScript

2020-11-12 10:20:40

前端面試web

2019-05-15 16:45:13

SpringBoot面試題Java

2020-11-06 09:05:18

前端web開發(fā)

2018-03-08 18:40:47

Java百度面試題

2020-08-06 10:45:30

JavaSpring面試題

2022-07-08 08:21:26

JSbind 方法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)