咱們在開開心心作幾道JavaScript機試題 - 01中吐了槽,也順勢展開了機試題之旅,本章咱們暫時壓抑本身的吐槽之心,繼續就題目前行。仍然但願對各位正確認識JavaScript
這門語言,已經在面試過程當中遇到這些問題時,如何思考!javascript
項目地址:fe-interviewjava
本題主要考查對數組的工具函數的理解、認識。不少朋友習慣了遇事兒就噴一堆
for loop
在那噁心人,忽略變量污染、沒必要要的遍歷操做、含義模糊等問題可能帶來的潛在隱患。對抱有這種錯誤認識的朋友,只要考考這些常見的數組快捷函數的實現原理,原形畢露!^^git
答案:程序員
var find = function(array, func) { for (var i = 0; i < array.length; i++) { if (func(array[i], i)) { return array[i]; } } }; module.exports = find;
關於這一點,能夠閱讀:Functional programming in Javascript: map, filter and reduceangularjs
本題和上題的惟一區別在於,尋找最後一個符合條件的指定元素github
答案:面試
var findlast = function(array, func) { for (var i = array.length - 1; i > -1; i--) { if (func(array[i], i)) { return array[i]; } } }; module.exports = findlast;
這個考察的就是對數組和
literal object
的組合使用正則表達式
答案:redis
var findmost = function(array, identity) { var occurrence = {}; var most; for (var i = 0; i < array.length; i++) { var item = array[i]; var id = identity ? identity(item) : item; if (!occurrence[id]) { occurrence[id] = {count: 1, raw: item}; } else { occurrence[id].count++; } if (!most || (most !== id && occurrence[id].count > occurrence[most].count)) { most = id; } } return occurrence[most].raw; }; module.exports = findmost;
我只用了
for loop
形式,歡迎更簡潔寫法的PRexpress
本題考查了兩個數組的比較,查找第二數組裏沒有出現的第一個數組的元素。其中對
isNaN
有比較細節的針對
答案:
var isNaN = Number.isNaN; var difference = function(arr1, arr2) { return arr1.reduce(function(previous, i) { var found = arr2.findIndex(function(j) { return j === i || (isNaN(i) && isNaN(j)); }); return (found < 0 && previous.push(i), previous); }, []); }; module.exports = difference;
個人答案用了
reduce
來獲取最終結果;若是有朋友對found < 0 && previous.push(i)
不明白,能夠看:短路求值。若是對,
的使用不了解,那說明你沒看上一章
本題考查對字符串的各類處理手段
答案:
var camelcase = function(str) { return str.toLowerCase() .replace(/(\s+|-+)(.)/g, function(matched, separator, letter) { return letter.toUpperCase(); }); }; module.exports = camelcase;
我這裏用了一套組合技,先
toLowerCase
,再配合正則表達式,用一個replace
結束戰鬥
本題考查了對數組便捷函數的理解認識,重點在於第二個參數是
callback
,不少人都被String
和Boolean
給嚇到了,想不通爲何結果會是那個樣子。其實String和Boolean都是構造函數,能夠直接調用的。
答案:
var times = function(n, func) { return Array .apply([], new Array(n)) .map(function(item, index) { return func(index); }); }; module.exports = times;
很少說了,依舊圍繞數組。雖然數組的題比較多,但在面試過程當中能夠選擇作答,沒必要所有都寫
答案:
var filter = function(arr, iteratee) { return arr.reduce(function(previous, item) { return (iteratee(item) && previous.push(item), previous); }, []); }; module.exports = filter;
個人答案仍然利用了
reduce
和短路求值
這個題目對部分朋友來講,可能又過度了。但相信我,題目不是爲了羞辱誰,而是考察關於
JavaScript
,你到底知道多少?函數式編程不是寫Javascript
的必需條件,但函數式表達的簡潔性,對於代碼更深刻的理解仍是頗有幫助的。
關於什麼是thunk
?咱們先來看看簡單定義:「一個封裝了特定行爲使其能夠延遲執行的函數,一般咱們稱之爲thunk
」,若是但願瞭解更多關於thunk
的內容,看Thoughts On Thunks
答案:
var thunkify = function(func) { return function() { var _this = this; var args = Array.prototype.slice.call(arguments); return function(cb) { try { func.apply(_this, args.concat([cb])); } catch (e) { cb(e); } }; }; }; module.exports = thunkify;
關於
arguments
爲何須要Array.prototype.slice.call(arguments)
轉換成Array
,看arguments
答案:
var zipobject = function(arr1, arr2) { return arr1.reduce(function(previous, key, index) { return (previous[key] = arr2[index], previous); }, {}); }; module.exports = zipobject;
本題考查數組合並/壓縮,我用了
reduce
來處理。經過最近這幾題能夠看出來,reduce
真的能作不少事情哦!
本題考查對「緩存」的理解,不少人會被這個概念唬住,覺得又是什麼瀏覽器緩存啦,服務器緩存啦,甚至有人想到了
redis
、memcached
等工具,而後被嚇得半死。其實沒那麼牛逼,你就是寫一個變量,只要不銷燬,均可以叫緩存。
答案:
var once = function(func) { var value, executed; return function() { var args = Array.prototype.slice.call(arguments); if (!executed) { executed = true; value = func.apply(this, args); return value; } return value; }; }; module.exports = once;
經過設置一個
executed
的標記來判斷該函數是否已經執行過了
本題考查對
map
的理解。
答案:
var flatmap = function(array, iteratee) { return Array.prototype.concat.apply([], array.map(iteratee)); }; module.exports = flatmap;
一個小技巧,對於二維數組,利用
concat
函數處理,代碼更簡潔
多少人寫了好久的
express
,結果搞不清middleware
是什麼,怎麼工做的,如何書寫middleware
,怎麼使用middleware
。這一切都源於對「中間件」這個概念的模糊,以及對express
中「中間件」的實現原理的不解
答案:
var Middleware = function() { this.pool = []; }; Middleware.prototype.use = function(cb) { this.pool.push(cb.bind(this)); }; Middleware.prototype.start = function(cb) { var _this = this; var pullOut = function() { if (_this.pool.length === 0) { return cb.call(_this); } _this.pool.shift()(pullOut); }; pullOut(); }; module.exports = Middleware;
關於
middleware
的詳細介紹,能夠看guide。
本題考查對
URl
的理解,各部分都是什麼意思。在咱們過往的經歷中,常常發現候選人搞錯一些概念,譬如:什麼是query parameter
,protocol
指的是哪一段,domain
又是哪一段,咱們常說的hash/fragment
是什麼?分清楚各部分是什麼,方便分解這道題
關於URL
,你可能想看到以下圖解:
答案:
var urlparser = function(url) { var result = /^(?:(https?):)\/\/([\.\-\w]+)(?:([\/\w]+))?(?:\?([\w=&]+))?$/.exec(url); var parsed = {protocol: result[1], host: result[2]}; if (result[3]) { parsed.path = result[3]; } if (result[4]) { parsed.query = result[4].split('&') .map((query) => query.split('=')) .reduce((params, pairs) => (params[pairs[0]] = pairs[1], params), {}); } return parsed; }; module.exports = urlparser;
這個答案我用了正則和
map
、reduce
,略顯臃腫。強烈歡迎更優解法
這又是個有故事的題,關於「節流閥」,是一種下降計算頻率的處理。最多見的使用場景:當頁面滾動時計算某一個值,相信若是你直白的在
onScroll
裏寫了計算行爲後會發現,每移動一個像素都會觸發一次計算,若是計算量還有一點大的話,卡不死你。這時候就用到了節流閥
的技巧。關於「節流閥」更多詳情,請看throttle
答案:
var throttle = function(func, wait) { var last, timer; return function() { var args = Array.prototype.slice.call(arguments); var _this = this, now = new Date().getTime(); if (typeof last === 'undefined') { last = now; return func.apply(_this, args); } clearTimeout(timer); if (now - last > wait) { last = new Date().getTime(); return func.apply(_this, args); } timer = setTimeout(function() { last = new Date().getTime(); func.apply(_this, args); }, wait + last - now); }; }; module.exports = throttle;
用過
AngularJS
的朋友確定都見識到了「依賴注入」的威力(固然若是你是java轉型的程序員,更應該有體會),依賴注入是一種解藕手段,咱們在java中一般如是介紹:「依賴注入是實現IoC
(控制反轉)一種方式」。關於依賴注入,你也能夠看手寫依賴注入
答案:
var Di = function() { this.instanceStore = {}; }; Di.prototype.register = function(name, inst) { this.instanceStore[name] = inst; }; Di.prototype.run = function(arr) { var _this = this, lastIndex = arr.length - 1; arr[lastIndex].apply(null, arr.slice(0, lastIndex) .map(function(name) { var Inst = _this.instanceStore[name]; if (!Inst) { throw new Error('You are expecting a non-exist instance'); } return typeof Inst === 'function' ? new Inst() : Inst; })); }; module.exports = Di;
注意我在
run
實現裏的typeof Inst === 'function' ? new Inst() : Inst;
使得若是註冊的是一個構造函數,那麼每次使用都會注入一個新的實例,這和AngularJS
裏使用單例的策略不一樣,這裏留下一個問題,若是我但願使用單例策略,答案要作如何修改?
這是餘下的15個題目,隨時歡迎PR,歡迎指正,歡迎優化。