開開心心作幾道JavaScript機試題 - 01

咱們在長期的面試過程當中,經歷了種種苦不堪言,不訴苦感受不過癮(我儘可能控制),而後主要聊聊常見JavaScript面試題的解法,以及面試注意事項javascript

憶苦

面試第一苦,面試官的土 - 有些面試官本身就很是不專業,詞不達意、不知所云,這類面試經常表現爲網上搜題,面試時照本宣科,只會比較候選人的答案最終的結果,自動忽略候選人對題目的看法以及解題思路。碰到這種面試官,你只有是個題霸,再加上眼緣夠才能順利入圍。苦!html

面試第二苦,候選人的虎 - 有些候選人的表現好像菜市場的大媽,表述永遠走「樸實無華」路線,譬如:說個iife,他必定要說「就是那個小括號包裹,裏面寫一個函數,最後再來一對括號,函數裏面寫一堆閉包的寫法」, 注意,這裏面必定會說「裏面寫閉包」這句話,以彰顯專業性,卻不知從一開始就露怯了。苦!java

面試第三苦,雙方都在賭 - 面試官自說自話,候選人答非所問,場面一片歡愉,結果不言而喻!git

面試,是一個很是須要認真思考的事情,不管面試官仍是候選人,選什麼人、怎麼選;面什麼公司、什麼崗位、題目不會該如何做答?不思考胡說一通,那不苦纔有鬼!程序員

一般面試都是聊天、筆試,機試環節經常短缺。但捫心自問,咱們真的須要程序員熟背全部Javascript API麼?咱們真的須要程序員熟背全部Web API麼?咱們真的須要程序員瞬間給出「某某網站慢的徹底優化方案」麼?github

我在想,前兩問徹底能夠Google,考察的重點不在於候選人能默寫多少API,而在於當他記不住的時候,是否知道去哪裏查!關於後一問,瞬間給出徹底優化方案?別鬧了,你本身面對這個產品那麼些年也沒搞定,別人在沒有任何瞭解的狀況下,看一眼(有時連看都沒看着,僅聽描述)就能給出方案,那大家公司養的都是廢物吧?這裏考察的重點應該是思路,候選人會從哪幾個方面思考問題的癥結所在,至因而否能給出解決方案,我以爲可能性不大,一個產品涉及的東西太多,離開背景細節,給出解決方案的可能性不大。面試

覺醒

缺乏上機測試會有什麼問題?(其實沒什麼大差錯),不過可能會損失一些「嘴笨」的實踐派幹活能手,他們信奉「能動手就別BB」,這類人一般在與面試官face 2 face的「聊天」中不能討得面試官歡心,但他們真心能寫的一手好碼,惋惜沒機會展現,也是苦!算法

因而我以爲你們應該互相給對方一個機會,談談我本身用的一套機試題目fe-interview,以及做爲面試官但願瞭解的候選人關於Javascript方面的能力的見解。segmentfault

如下是該機試題目的開始界面(retro風格),經過鍵盤光標上/下鍵選擇題目,按回車鍵確認選中數組

雖然寫了「算法考覈」,但其實沒什麼算法題,這也算是標題黨吧^^

圖片描述

確認選中後,會出現以下選擇器,候選人能夠再次上/下鍵選擇"查看題目描述"、「查看測試用例」、「檢驗答題結果」

圖片描述

"查看測試用例"的目的是幫助候選人,經過查看測試用例的代碼來改進本身的題目解答。

該測試工具須要本地安裝,詳情請看:安裝/使用手冊

簡單瞭解測試工具以後,咱們就能夠開始愉快的答題了

最後再來回顧一下機試目標:機試的目的不是爲了讓候選人在指定時間內完成一個完美無瑕的功能,那是高考!咱們期待的是經過不一樣的題目,考察候選人的基本功、編碼能力、思考方法。。。,經過這些綜合指標,判斷該候選人是否一個你指望的JavaScript工程師

下面讓咱們一塊兒走上答題之路

答題之路

01 - 請嘗試刪除數組的指定下標對應的元素

圖片描述

題目很是簡單,完成一個能夠刪除數組指定下標對應元素的函數

答案:

var removeArray = function(arr, index) {
    arr.splice(index, 1);
};

module.exports = removeArray;

真心沒什麼花哨的地方,這個題目不涉及任何高深的知識。旨在考察候選人對基礎API的熟練程度,關於splice你可能想知道更多

02 - 請嘗試完成能夠判斷傳入變量是否爲string的模塊

圖片描述

答案:

var isString = function(value) {
    return Object.prototype.toString.call(value) === '[object String]';
};

module.exports = isString;

這裏考察的重點是new String('hello')究竟是個什麼東西?至於我給的答案用了Object.prototype.toString方法,我能夠負責任的告訴你,這個作法是有風險的,由於該方法的實現由平臺提供,意思是:不一樣的JavaScript執行引擎實現可能不一樣,因此結果並不能保證。仍是那句話,結果不是最重要的,解題思路,看清本質最爲關鍵,也是最重要的能力。固然關於Object.prototype.toString,你也可能想知道更多

03 - 請嘗試完成一個簡單的使柯里化(currying)模塊

圖片描述

這題可能對一些同窗來說有點過了,但相信我,個人測試用例並不變態,你徹底沒必要寫出一個「完美」的柯里化。只要按照我題目的思路,甚至打出來測試用例看看,就能實現這個題目了。

首先爲了普法,仍是先簡單介紹下什麼是「柯里化」,說白了柯里化也是一個函數。假設咱們有函數A通過柯里化函數處理事後,A就被賦予了一種可以被部分執行的能力!這話說的聽不懂了是吧?咱們來看個例子:

//假設咱們有個add函數,她接受兩個參數a和b;並返回兩者之和
var add = function(a, b){
    return a + b;
};

簡單吧?那麼問題來了,若是我如今只給了你一個參數a,另外一個參數我想過會兒再給你,怎麼辦?傳統思惟是那就過一會再調用add唄!這固然沒錯!可是憑藉柯里化,咱們有另一種思路使得如下成爲可能:

var add3 = add(3);//執行了一半

setTimeout(function(){
    console.log(add3(5));//這裏拿到了另外一半參數5,再計算最終結果
}, 5000);

我這裏不會大篇幅講柯里化有多牛逼的好處,固然若是你有興趣,能夠看Why Curry Helps

答案:

var currying = function(func) {
    var len = func.length;//獲取一個函數形參的個數

    var getCurry = function(params) {
        return function() {
            //參數拼接
            var next = params.concat(Array.prototype.slice.call(arguments));
            //持續接收的參數已經知足當初原始函數的形參個數,執行原始函數,返回結果
            if (len - next.length <= 0) {
                return func.apply(this, next);
            }
            //不知足個數,將已經獲取的參數繼續遞歸
            return getCurry(next);
        };
    };

    return getCurry([]);
};

module.exports = currying;

04 - 請嘗試完成一個'duplicate(重複)'的模塊

圖片描述

如此簡單的題目,我想考察的依舊是Array的內置API,不記得沒關係,我是容許上網查的(誰沒有個記不住的時候)。但你要是玩出花來,譬若有人寫了幾十行的方法,這個我就有點懵了。

答案:

var duplicate = function(array) {
    return array.concat(array);
};

module.exports = duplicate;

其實concat足矣。關於concat更多詳情

05 - 請嘗試完成能夠淺拷貝的模塊

圖片描述

「淺拷貝」,顧名思義,對於引用類型的數據,只拷貝其引用,也就是題目中copied[0].name = 'world';以後,原先的value也被改了。

答案:

var shallowCopy = function(value) {
    return Object.assign(new (Object.getPrototypeOf(value).constructor)(), value);
};

module.exports = shallowCopy;

根據@Tommy Troy Lin的PR,對答案作出修正。緣由是我在題目裏提到了對Object的支持,而個人答案以及題目考覈的最初想法都沒有考慮Object的狀況(記憶錯亂了)。再次感謝指正

關於Object.assign,不明白的同窗看這裏assign;對於Object.getPrototypeOf不清楚的同窗,看getPrototypeOf

06 - 請嘗試完成一個相似'_.flatten'的模塊

圖片描述

如何「拍平」一個多維數組,這是好玩意兒

答案:

var flatten = function(array) {
    return array.reduce(function(previous, i) {
        if (Object.prototype.toString.call(i) !== '[object Array]') {
            return (previous.push(i), previous);
        }
        return (Array.prototype.push.apply(previous, flatten(i)), previous);
    }, []);
};

module.exports = flatten;

本題在「遞歸」這個問題上,作了一些考慮。我想考查的主要是面對多維數組,候選人將如何處理!

個人答案用了reduce方法,若是你還沒用過,你須要看reduce。另外可能有人對於逗號的使用有疑惑,能夠看Comma_Operator。另:個人答案毫不敢稱最佳,隨時歡迎優化/修正。

07 - 請嘗試完成一個'繼承'的實現

圖片描述

考查ES5時代基於prototype的類繼承實現,若是你心繫ES6,這個能夠忽略。但瞭解總歸是好的

答案:

Parent

var Parent = function(name) {
    this.name = name;
};

Parent.prototype.getName = function() {
    return this.name;
};

module.exports = Parent;

Son

var Parent = require('./Parent');

var Son = function(parentName, name) {
    Parent.call(this, parentName);
    this.childName = name;
};

Son.prototype = Object.create(Parent.prototype);

Son.prototype.constructor = Son;

Son.prototype.getChildName = function() {
    return this.childName;
};

module.exports = Son;

以上算是基本繼承概念,若是不清楚的,看看這篇教程OOP in JS, Part 2 : Inheritance。你也可能對與Object.create的使用感到疑惑,那麼請看create

接受@我仍舊在這裏 建議,把new Parent()換成了Object.create(Parent.prototype)

08 - 請嘗試完成一個相似'_.map'的模塊

圖片描述

經過長期觀察咱們發現一個現象,就是在ES2015甚至ES2016大行其道的今天,仍然有人打着「我要兼容IE8」的旗號拒絕進步。自ES5開始就有的Array新方法map, forEachreduce經常有人搞不懂,也不會用,更不知道幹嗎用的。每每一言不和就吐一堆for循環出來噁心人!本題主要就是甄別候選人是否本身口中所說的那樣「積極、愛學習」,若是連ES5就有的常見方法都不會,仍是「積極、愛學習」,那我只能呵呵了!

答案:

var map = function(arr, func, ctx) {
    var array = [];

    arr.forEach(function(i, index) {
        array.push(func.call(ctx, i, index, arr));
    });

    return array;
};

module.exports = map;

這裏解法也是多種多樣,無所謂用哪種,關鍵在因而否真正理解了什麼是map?文檔看:map

09 - 請嘗試完成一個相似'_.reduce'的模塊

圖片描述

最爲ES5Array的幾個好兄弟,reduce的用法/原理我想仍是應該掌握的。

答案:

var reduce = function(arr, func, initialValue) {
    var base = typeof initialValue === 'undefined' ? arr[0] : initialValue;
    var stepForward = typeof initialValue === 'undefined' ? 1 : 0;
    var startPoint = stepForward;
    arr
        .slice(startPoint)
        .forEach(function(val, index) {
            base = func(base, val, index + stepForward, arr);
        });
    return base;
};

module.exports = reduce;

仍然不理解reduce工做原理的,看Understanding Eloquent Javascript's Reduce function

10 - 請嘗試完成一個獲取原始數據值的模塊

圖片描述

永遠獲取傳入參數的最終執行結果,若是是函數的,就執行、執行、再執行,直到拿到了最終的非函數結果。

答案:

var value = function(anything) {
    if (Object.prototype.toString.call(anything) !== '[object Function]') {
        return anything;
    }
    return value(anything());
};

module.exports = value;

今天實在寫不動了,先來10題試試反響,若是你們以爲還有用,我再繼續補後面的題目。固然也歡迎直接Github給我PR,star那天然是最好的啦^^

欲知後事,請看下集

相關文章
相關標籤/搜索