頭條二面


  還是要diss一下周六的平安總部面試,面試體驗渣到極點,以至於我已經在心里把所有平安職位拉黑。

  二面直接放點題目吧,作為記錄,所有題目都需要現場手寫,痛苦。

 

  自我介紹的時候,面試官問了下有什么東西特別有成就感,我就說原生實現了Datepicker的插件,然后就開始特別細節的問。

  源代碼比較長,貼個地址吧:https://github.com/pflhm2005/JS-components/blob/master/vanilla-picker/index.js

  這一塊問了比較久,因為完全是自己寫的,所以全部都能答出來。

  接下里是現場出題。

  

1、實現JSON.stringify的polyfill

  想了老久,手寫很痛苦,就講思路了。

  普通類型略,復雜類型根據對象、數組做遍歷,然后用'{'、'}'、'['、']'字符進行拼接,中間涉及到null、undefined,直接跳過。

  還有一個循環引用的問題,需要直接報錯,問題是如何判斷存在循環引用,這里貼一個自己寫的深拷貝代碼,里面有處理循環引用的思路:

const deepClone = (o) => {
  let path = new WeakMap();
  path.set(o, 'this');
  let path_ar = ['this'];
  return (function inner(o) {
    let result = {};
    Object.keys(o).forEach(v => {
      let value = o[v];
      path_ar.push(v);
      if(value && typeof value === 'object') {
        if (path.has(value)) {
          let dupi_path = path.get(value).split('.').slice(1);
          let origin = result;
          dupi_path.forEach(v => {
            origin = origin[v];
          });
          result[v] = origin;
        } else {
          path.set(value, path_ar.join('.'));
          result[v] = inner(value);
        }
      } else {
        result[v] = value;
      }
      path_ar.pop();
    });
    return result;
  })(o);
};

  因為拿深拷貝的循環引用處理講的,面試官就問我這個深拷貝后的對象,循環引用還指向之前的么,我就回答新對象中所有屬性跟老的完全無關。

 

2、嵌套數組的環形遍歷

  這個題目有點意思,直接上圖:

  比如說上面這個二維數組,可以理解成一個矩陣,然后遍歷方式如下:

  一圈圈從外向內遍歷,當然題目是m*n的矩陣。

  一開始看到題目感覺也挺新鮮,細寫發現好惡心,變量用不過來,就簡單講了下思路,大概是設定一個遍歷規則,然后遍歷的初始和終止條件,嵌套for循環搞定。

  回家后寫了下,代碼如下:

let iterator = (ar) => {
  let m = ar.length;
  let n = ar[0].length;
  for(let i = 0,j = n;i !== j;i++,j--,m--) {
    for(let i2=i;i2<j;i2++) {
      console.log(ar[i][i2]);
    }
    for(let i3=i+1;i3<m;i3++) {
      console.log(ar[i3][m-1]);
    }
    for(let i4=j-1;i4>i;i4--) {
      console.log(ar[m-1][i4-1]);
    }
    for(let i5=m-2;i5>i;i5--) {
      console.log(ar[i5][i])
    }
  }
}

  這TM現場手寫,怕是要瘋了。

 

3、sum(1,2).value()、sum(1)(2).value()均返回3

  這里一眼就看出來是函數柯里化,但是下手的時候很懵逼。

  想了好久好久,面試官都有點看不下去了,最后寫出來了(完整手寫出來,真的不容易啊):

function sum(...args){
  let n = args.reduce((a,b) => a+b, 0);
  function inner(...args2){
    return sum.apply(null, [n, ...args2]);
  }
  inner.value = () => { console.log(n); };
  return inner;
}

  面試官看了會,說寫的倒不錯,但是內部函數每次都會創建一個閉包,有沒有優化的辦法。

  我一臉痛苦的看了他一眼,他想了想說算了。

  這里貼一個優化版的,不知道符不符合面試官要求:

let sum = (...args) => {
  let result = [...args];
  return (function(r) {
    let inner = (...args) => {
      r.push(...args);
      return inner;
    }
    inner.value = () => { console.log(r.reduce((a,b) => a+b, 0)); };
    return inner;
  })(result)
};

  緩存一個數組,每次調用都返回同一個內部函數,不會重復走大函數流程,錯了我就刪掉。。。

 

4、字符串駝峰化

  簡單講就是aa-bb => aaBb,aa--bb => aaBb。

  先是簡單的版本:

function camel(str) {
  let ar = str.split('-');
  let result = [];
  let l = ar.length;
  for(let i = 1;i < l;i++) {
    if(!ar[i]) continue;
    result.push(ar[i][0].toUpperCase() + ar[i].slice(1));
  }
  return ar[0] + result.join('');
}

  然后面試官說,可能分隔符有多種,比如說_、@等等,然后函數不變,仍然只能傳一個參數。

  我說這得重寫,我的第一行就不管用了。

  面試官讓講思路,我就簡單說直接遍歷,設一個flag,標記是否遇到了分隔符,然后把分隔符后面的第一個非分隔符大寫。

  回家后,代碼如下:

// 假設分隔符有_和-兩種
function camel(str) {
  let cut = ['_', '-'];
  let ar = str.split('');
  let l = ar.length;
  let flag = false;
  for(let i = 0;i < l;i++) {
    let cur = ar[i];
    if(cut.indexOf(cur) !== -1) {
      ar[i] = '';
      flag = true;
    }
    else if(flag){
      ar[i] = ar[i].toUpperCase();
      flag = false;
    }
  }
  return ar.join('');
}

   后面就問了一些工程化的問題(cdn、渲染優化),我一個都不會,果然還是太年輕。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM