2018.5 一週面試題

楊季布發表於2018-08-05

1、傳統佈局和flex佈局有什麼區別?

答:css盒子模型是所有佈局共同的,不是某個佈局專屬的。目前主流的佈局有兩類,一類是基於格子布局,將頁面看成行+列的二維佈局。另一類是flex佈局,將頁面看成行或者列的一維佈局。
效能上flex允許子元素不設定寬高,而是演算法動態去計算,效能會比設定好的慢一些,但在這個時代沒有大影響。但計算結果有時候會不符合預期,需要flex提供屬性給與啟發。
div + css、基於table的佈局
擴充:grid、多列布局的多種方法、flex的歷史寫法、哪些瀏覽器支援-webkit-box、flex是w3c提議的還是標準、什麼是佈局、flex在移動端的相容性
https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout
複製程式碼

2、你對vue原始碼瞭解嗎?雙向繫結是怎麼實現的?詳細描述什麼時候監聽變化、什麼時候觸發變法?

答:
參考網址:https://juejin.im/post/5af8eb55f265da0b814ba766
複製程式碼

3、如何比較兩個顏色的相似性?

答:這是一道開放題目,首先將顏色拆分成r/g/b三個值,如果是字串的顏色如#aabbff或者rgb(255,128,100)可以用正規表示式取出對應的r/g/b值。對於16進位制字串,可以使用parseInt('0xaa')轉10進位制整數。然後對於兩個顏色,可以使用距離 Math.sqrt( (r1-r2) *(r1-r2) +(g1-g2)*(g1-g2)+(b1-b2)*(b1-b2) )進行比較, 距離近則相似。 當然可以用Math.hypot( r1-r2, g1-t2, b1-b2) 來簡化上述運算。
這道題目主要考察學員的知識積累和思考。 首先要知道rgb是顏色的組成。 然後要給出一種可行的比較方法。 最後要考察具體javascript細節函式的運用。
複製程式碼

4、一個單頁面應用,有6張頁面,F、E、A、B、C、D。 頁面ABCD構成了一個冗長的使用者驗證過程。目前A、B、C對應使用者驗證過程的第1步,第2步,第3步。 頁面F是首頁,E是某張業務相關頁面。使用者到達頁面E後,系統發現使用者沒有認證,觸發驗證流程,到達頁面A,然後開始A->B->C->D流程。 頁面D是驗證結果頁面(驗證成功頁面)。 請問,如果到達頁面D後,如何讓使用者點選返回可以返回頁面F,而忽略中間流程(注:使用者可能根本沒有到達過F,比如微信分享直接進入了E)。

答: 這個問題初一看是對單頁面路由架構的考察。也是一個很好的引入問題,可以考察非常多方面。 比如說:如何實現頁面切換動畫? A、B、C都是表單的話,如何快取使用者輸入完成的表單資料?……回到問題,因為history api提供了push/pop/replace三種操作,無論是其中的任何一種都無法實現上述的效果。 一個路由系統,首先要監聽瀏覽器地址的變化,然後根據變化渲染不同的頁面。1. 在頁面到達D後,關閉對路由變化頁面渲染的監聽。 2. 路由系統要進行多次POP,可以用history.go(-n)實現; 3. 路由棧清空到只剩下一張頁面時,將這張頁面替換為F。 4. PUSH一張頁面D。 5. 如果在HTML上有一個類似「輪播圖」的設計,就是每一張頁面是一張輪播圖,將輪播圖設定成只有「F」和「D」。 5. 恢復路由監聽。 這個問題的另一個考點是,在上述完整的計算過程當中,需要知道當前歷史記錄中的頁面數,頁面數可以通過localStorage實現,在ls中維護一個變數,每次push的時候+1,並寫入history.state。 POP的時候讀取history.state將變數重置。
複製程式碼

5、一個無序正負項 陣列, eg:[3, -6, 123, -945, -231, 112] 找出其中的最大的連續子序列

有如下亂序陣列 A1, A2, A3, A4,........An, 求 i, j (1<= i <= j<= n), 使得Ai + .... + Aj 和最大, 輸出i j

答:思路:假設答案是i,j;那麼第一個數到第i-1個數之和一定是一個負數;。最大子序列兩端的端點到整個陣列的斷點的值之和 一定是負數。
複製程式碼

6、函式的節流與防抖

答:你是否在日常開發中遇到一個問題,在滾動事件中需要做個複雜計算或者實現一個按鈕的防二次點選操作。
這些需求都可以通過函式防抖動來實現。尤其是第一個需求,如果在頻繁的事件回撥中做複雜計算,很有可能導致頁面卡頓,不如將多次計算合併為一次計算,只在一個精確點做操作。因為防抖動的輪子很多,這裡也不重新自己造個輪子了,直接使用 underscore 的原始碼來解釋防抖動。
整體函式實現的不難,總結一下。
對於按鈕防點選來說的實現:一旦我開始一個定時器,只要我定時器還在,不管你怎麼點選都不會執行回撥函式。一旦定時器結束並設定為 null,就可以再次點選了。
對於延時執行函式來說的實現:每次呼叫防抖動函式都會判斷本次呼叫和之前的時間間隔,如果小於需要的時間間隔,就會重新建立一個定時器,並且定時器的延時為設定時間減去之前的時間間隔。一旦時間到了,就會執行相應的回撥函式。
節流
防抖動和節流本質是不一樣的。防抖動是將多次執行變為最後一次執行,節流是將多次執行變成每隔一段時間執行。
/**
 * underscore 節流函式,返回函式連續呼叫時,func 執行頻率限定為 次 / wait
 *
 * @param  {function}   func      回撥函式
 * @param  {number}     wait      表示時間視窗的間隔
 * @param  {object}     options   如果想忽略開始函式的的呼叫,傳入{leading: false}。
 *                                如果想忽略結尾函式的呼叫,傳入{trailing: false}
 *                                兩者不能共存,否則函式不能執行
 * @return {function}             返回客戶呼叫函式   
 */
_.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    // 之前的時間戳
    var previous = 0;
    // 如果 options 沒傳則設為空物件
    if (!options) options = {};
    // 定時器回撥函式
    var later = function() {
      // 如果設定了 leading,就將 previous 設為 0
      // 用於下面函式的第一個 if 判斷
      previous = options.leading === false ? 0 : _.now();
      // 置空一是為了防止記憶體洩漏,二是為了下面的定時器判斷
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      // 獲得當前時間戳
      var now = _.now();
      // 首次進入前者肯定為 true
	  // 如果需要第一次不執行函式
	  // 就將上次時間戳設為當前的
      // 這樣在接下來計算 remaining 的值時會大於0
      if (!previous && options.leading === false) previous = now;
      // 計算剩餘時間
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // 如果當前呼叫已經大於上次呼叫時間 + wait
      // 或者使用者手動調了時間
 	  // 如果設定了 trailing,只會進入這個條件
	  // 如果沒有設定 leading,那麼第一次會進入這個條件
	  // 還有一點,你可能會覺得開啟了定時器那麼應該不會進入這個 if 條件了
	  // 其實還是會進入的,因為定時器的延時
	  // 並不是準確的時間,很可能你設定了2秒
	  // 但是他需要2.2秒才觸發,這時候就會進入這個條件
      if (remaining <= 0 || remaining > wait) {
        // 如果存在定時器就清理掉否則會呼叫二次回撥
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // 判斷是否設定了定時器和 trailing
	    // 沒有的話就開啟一個定時器
        // 並且不能不能同時設定 leading 和 trailing
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };
複製程式碼

extra: json web token,jwt

相關文章