JavaScript技術面試時要小心的三個問題

前言

JavaScript是所有現代瀏覽器的官方語言。同樣的,JavaScript面試題出現在各種各樣的面試中。

這篇文章不是講述JavaScript最新的庫、日常的開發實踐,或是ES6的新功能。當然了,上面說的這3點經常出現在JavaScript的面試中。我自己也曾經問過面試者這些問題,我的朋友告訴我,他們同樣也是。

當然,你去面試前不能只準備上面提到的3點,這里有許多方法讓你能夠更好的面對即將到來的面試。

但是,接下來的這3個問題,面試官可能會根據你的回答,去判斷你對JavaScript和DOM的了解程度。

所以,現在開始吧!請注意,我們在接下來的例子中將使用原生JavaScript,因為你的面試官可能想看看在沒有第三方庫的情況下,比如jQuery,你對JavaScript和DOM的理解程度。

問題 #1: 事件委托

當構建一個程序時,有些時候你需要監聽按鈕、文本、圖片的事件,因為當用戶與界面元素發生互動時,你需要執行一些動作。

如果我們拿到一個簡單的待辦事項列表,就像下面例子中這樣,面試官可能會告訴你,當用戶點擊其中一個列表項時,我們需要執行一些動作。面試官希望你用JavaScript實現這個功能,假設HTML代碼如下:

<ul id="todo-app">
  <li class="item">Walk the dog</li>
  <li class="item">Pay bills</li>
  <li class="item">Make dinner</li>
  <li class="item">Code for one hour</li></ul>

你也許會像下面這樣去給這些元素綁定事件監聽:

document.addEventListener('DOMContentLoaded', function() {

  let app = document.getElementById('todo-app');
  let items = app.getElementsByClassName('item');

  // 給每個列表項綁定事件監聽器
  for (let item of items) {
    item.addEventListener('click', function() {
      alert('you clicked on item: ' + item.innerHTML);
    });
  }});

雖然實現了功能,但問題是我們給每個列表項都單獨綁定了事件監聽。現在只有4個元素,沒問題,但是如果有10000個待辦事項呢(程序可能還有其他事情要做)?接下來你會創建10000個事件監聽函數綁定要每個DOM元素上,這是十分低效的。

在面試時,最好問問面試官用戶可以輸入的最大元素數量。如果數量小于10個,上面的例子可以很好的運行。但是如果數量不受限制,你可能需要使用一個更有效率的解決辦法。

如果你的應用有數百個事件監聽,更有效率的解決辦法是:把事件監聽綁定在包裹這些元素的容器上,當元素被點擊時,我可以得到當前點擊的確切元素。這種技巧叫事件委托,而且它比給每個元素綁定事件監聽效率要高。

用事件委托的方式實現上面的功能:

document.addEventListener('DOMContentLoaded', function() {

  let app = document.getElementById('todo-app');

  // 把事件監聽器綁定在它們的容器上
  app.addEventListener('click', function(e) {
    if (e.target && e.target.nodeName === 'LI') {
      let item = e.target;
      alert('you clicked on item: ' + item.innerHTML);
    }
  });});

問題 #2: 在循環內使用閉包

閉包問題常常在面試中被提出,面試官能通過它估算出你對JavaScript的熟悉程度,同時了解你對閉包是否熟悉。

閉包的精髓就是:在外部函數中可以讀取到內部函數的作用域。閉包可以做這些事:創建私有變量、創建私有函數等。大多數關于閉包的面試題像這樣:

循環一個數組,并在3秒后打印出每個數組元素的索引。

一個通常的實現方式像下面這樣,但其實是錯誤的:

const arr = [10, 12, 15, 21];for (var i = 0; i < arr.length; i++) {
  setTimeout(function() {
    console.log('The index of this number is: ' + i);
  }, 3000);}

如果運行上面代碼你會發現,3秒后,每次循環輸出的都是4,而不是期望的0,1,2,3。

真正的去理解為什么會發生這些,它會幫助你更好的認識JavaScript,因為你也不知道面試官會出怎樣確切的題測試你。

出現上面現象的原因是:setTimeout會創建一個函數(就是閉包),它可以讀取到外部作用域,每個循環都包含了索引i。函數在3秒后執行,它打印出外部作用域中i的值,在循環結束后i等于4,因為它的循環周期經歷了0,1,2,3,4,最終在i為4時停止。

這里有幾種正確的方法去解決這個問題,下面列舉兩種:

const arr = [10, 12, 15, 21];for (var i = 0; i < arr.length; i++) {
  // 通過傳遞變量 i
  // 在每個函數中都可以獲取到正確的索引
  setTimeout(function(i_local) {
    return function() {
      console.log('The index of this number is: ' + i_local);
    }
  }(i), 3000);}
const arr = [10, 12, 15, 21];for (let i = 0; i < arr.length; i++) {
  // 使用ES6的let語法,它會創建一個新的綁定
  // 每個方法都是被單獨調用的
  // 詳情請移步至: //exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads
  setTimeout(function() {
    console.log('The index of this number is: ' + i);
  }, 3000);}

問題 #3: 函數防抖(Debouncing)

有些瀏覽器事件可以在很短的時間內執行多次,就像改變瀏覽器窗口尺寸和滾動頁面。如果你綁定一個事件去監聽窗口的滾動,用戶快速連續的滾動頁面,這個事件可能會在3秒內被觸發幾千次。這可能會導致很嚴重的性能問題。

如果你們在面試中討論構建一個應用,談到類似滾動、改變窗口尺寸或鍵盤按下的事件時,一定會提及函數防抖、函數節流(Throttling)去優化頁面速度和性能。一個真實的案例,來自guest post on css-tricks:

在2011年,一個問題在Twitter上被提出:當你滾動Twitter feed時,它會十分緩慢且遲鈍。John Resig就這個問題發布了一篇博客,它解釋了直接綁定函數到滾動事件上是多么糟糕和昂貴的事。

函數防抖是解決這個問題的一種方式,通過限制函數被調用的次數。一個正確實現函數防抖的方法是:把多個函數放在一個函數里調用,隔一定時間執行一次。這里有一個使用原生JavaScript實現的例子,用到了作用域、閉包、this和定時時間:

// debounce函數用來包裹我們的事件function debounce(fn, delay) {
  // 持久化一個timer
  let timer = null;
  // 閉包可以獲取到timer
  return function() {
    // 通過函數獲取到作用域和參數列表
    // 通過 'this' 和 'arguments'
    let context = this;
    let args = arguments;
    // 如果事件被觸發,清除timer并重新開始計時
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  }}

當這個函數綁定在一個事件上,只有經過一段指定的時間后才會被調用。

你可以像這樣去使用這個函數:

// 當用戶滾動時函數會被調用function foo() {
  console.log('You are scrolling!');}// 在事件觸發的兩秒后,我們包裹在debounce中的函數才會被觸發let elem = document.getElementById('container');elem.addEventListener('scroll', debounce(foo, 2000));

函數節流是另一個類似函數防抖的技巧,除了使用等待一段時間再調用函數的方法,函數節流還限制固定時間內只能調用一次。所以一個事件如果在100毫秒內發生10次,函數節流會每2秒調用一次函數,而不是100毫秒內全部調用。

來源:Rockjing Blog

上一篇: 2016前端探索總結——前端工程與未來

下一篇: HTML5有哪些優勢呢?參加HTML5培訓班是很有必要嗎?

分享到: 更多
百赢炸金花下载 时时彩倍投计划图 pk10冠亚和值全包法 河北时时开奖号码 球探比分网下载 棋牌龙虎怎么刷流水 玩分分赛车有什么技巧 大乐透篮球有13吗 时时彩全包方案 幸运28稳定模式 dnf挣钱快的方法 天天快三计划软件苹果 彩名堂pk10计划软件,在线软件 六肖中特心得 11选5万能10注 功夫时时彩网