頭條二面
還是要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、巢狀陣列的環形遍歷
這個題目有點意思,直接上圖:
Line"/>
比如說上面這個二維陣列,可以理解成一個矩陣,然後遍歷方式如下:
一圈圈從外向內遍歷,當然題目是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; }
面試官看了會,說寫的倒不錯,但是內部函式每次都會建立一個閉包,有沒有優化的辦法。
我一臉痛苦的看了他一眼,他想了想說算了。
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(''); }
後面就問了一些工程化的問題,我一個人都不會,果然還是太年輕。