资讯专栏INFORMATION COLUMN

开开心心做几道JavaScript机试题 - 02

seal_de / 2012人阅读

摘要:前集回顾我们在开开心心做几道机试题中吐了槽,也顺势展开了机试题之旅,本章我们暂时压抑自己的吐槽之心,继续就题目前行。其实和都是构造函数,可以直接调用的。请尝试完成一个解析模块本题考查对的理解,各部分都是什么意思。

前集回顾

我们在开开心心做几道JavaScript机试题 - 01中吐了槽,也顺势展开了机试题之旅,本章我们暂时压抑自己的吐槽之心,继续就题目前行。仍然希望对各位正确认识JavaScript这门语言,已经在面试过程中遇到这些问题时,如何思考!

项目地址:fe-interview

答题之路 11 - 请尝试完成一个类似"_.find"的模块

</>复制代码

  1. 本题主要考查对数组的工具函数的理解、认识。很多朋友习惯了遇事儿就喷一堆for loop在那恶心人,忽略变量污染、不必要的遍历操作、含义模糊等问题可能带来的潜在隐患。对抱有这种错误认识的朋友,只要考考这些常见的数组快捷函数的实现原理,原形毕露!^^

答案:

</>复制代码

  1. var find = function(array, func) {
  2. for (var i = 0; i < array.length; i++) {
  3. if (func(array[i], i)) {
  4. return array[i];
  5. }
  6. }
  7. };
  8. module.exports = find;

</>复制代码

  1. 关于这一点,可以阅读:Functional programming in Javascript: map, filter and reduce

12 - 请尝试完成一个类似"_.findlast"的模块

</>复制代码

  1. 本题和上题的唯一区别在于,寻找最后一个符合条件的指定元素

答案:

</>复制代码

  1. var findlast = function(array, func) {
  2. for (var i = array.length - 1; i > -1; i--) {
  3. if (func(array[i], i)) {
  4. return array[i];
  5. }
  6. }
  7. };
  8. module.exports = findlast;
13 - 请尝试完成一个查找出现频率最高元素的模块

</>复制代码

  1. 这个考察的就是对数组和literal object的组合使用

答案:

</>复制代码

  1. var findmost = function(array, identity) {
  2. var occurrence = {};
  3. var most;
  4. for (var i = 0; i < array.length; i++) {
  5. var item = array[i];
  6. var id = identity ? identity(item) : item;
  7. if (!occurrence[id]) {
  8. occurrence[id] = {count: 1, raw: item};
  9. } else {
  10. occurrence[id].count++;
  11. }
  12. if (!most || (most !== id && occurrence[id].count > occurrence[most].count)) {
  13. most = id;
  14. }
  15. }
  16. return occurrence[most].raw;
  17. };
  18. module.exports = findmost;

</>复制代码

  1. 我只用了for loop形式,欢迎更简洁写法的PR

14 - 请尝试完成一个类似"_.difference"的模块

</>复制代码

  1. 本题考查了两个数组的比较,查找第二数组里没有出现的第一个数组的元素。其中对isNaN有比较细节的针对

答案:

</>复制代码

  1. var isNaN = Number.isNaN;
  2. var difference = function(arr1, arr2) {
  3. return arr1.reduce(function(previous, i) {
  4. var found = arr2.findIndex(function(j) {
  5. return j === i || (isNaN(i) && isNaN(j));
  6. });
  7. return (found < 0 && previous.push(i), previous);
  8. }, []);
  9. };
  10. module.exports = difference;

</>复制代码

  1. 我的答案用了reduce来获取最终结果;如果有朋友对found < 0 && previous.push(i)不明白,可以看:短路求值。如果对,的使用不了解,那说明你没看上一章

15 - 请尝试完成一个类似"_.camelCase"的模块

</>复制代码

  1. 本题考查对字符串的各种处理手段

答案:

</>复制代码

  1. var camelcase = function(str) {
  2. return str.toLowerCase()
  3. .replace(/(s+|-+)(.)/g, function(matched, separator, letter) {
  4. return letter.toUpperCase();
  5. });
  6. };
  7. module.exports = camelcase;

</>复制代码

  1. 我这里用了一套组合技,先toLowerCase,再配合正则表达式,用一个replace结束战斗

16 - 请尝试完成一个类似"_.times"的模块

</>复制代码

  1. 本题考查了对数组便捷函数的理解认识,重点在于第二个参数是callback,很多人都被StringBoolean给吓到了,想不通为什么结果会是那个样子。其实StringBoolean都是构造函数,可以直接调用的。

答案:

</>复制代码

  1. var times = function(n, func) {
  2. return Array
  3. .apply([], new Array(n))
  4. .map(function(item, index) {
  5. return func(index);
  6. });
  7. };
  8. module.exports = times;
17 - 请尝试完成一个类似"_.filter"的模块

</>复制代码

  1. 不多说了,依旧围绕数组。虽然数组的题比较多,但在面试过程中可以选择做答,不必全部都写

答案:

</>复制代码

  1. var filter = function(arr, iteratee) {
  2. return arr.reduce(function(previous, item) {
  3. return (iteratee(item) && previous.push(item), previous);
  4. }, []);
  5. };
  6. module.exports = filter;

</>复制代码

  1. 我的答案仍然利用了reduce和短路求值

18 - 请尝试完成一个简单的thunkify函数

</>复制代码

  1. 这个题目对部分朋友来说,可能又过分了。但相信我,题目不是为了羞辱谁,而是考察关于JavaScript,你到底知道多少?函数式编程不是写Javascript的必需条件,但函数式表达的简洁性,对于代码更深入的理解还是很有帮助的。

关于什么是thunk?我们先来看看简单定义:“一个封装了特定行为使其可以延迟执行的函数,通常我们称之为thunk”,如果希望了解更多关于thunk的内容,看Thoughts On Thunks

答案:

</>复制代码

  1. var thunkify = function(func) {
  2. return function() {
  3. var _this = this;
  4. var args = Array.prototype.slice.call(arguments);
  5. return function(cb) {
  6. try {
  7. func.apply(_this, args.concat([cb]));
  8. } catch (e) {
  9. cb(e);
  10. }
  11. };
  12. };
  13. };
  14. module.exports = thunkify;

</>复制代码

  1. 关于arguments为什么需要Array.prototype.slice.call(arguments)转换成Array,看arguments

19 - 请尝试完成一个类似"_.zipObject"的模块

答案:

</>复制代码

  1. var zipobject = function(arr1, arr2) {
  2. return arr1.reduce(function(previous, key, index) {
  3. return (previous[key] = arr2[index], previous);
  4. }, {});
  5. };
  6. module.exports = zipobject;

</>复制代码

  1. 本题考查数组合并/压缩,我用了reduce来处理。通过最近这几题可以看出来,reduce真的能做很多事情哦!

20 - 请尝试完成一个类似"_.once"的模块

</>复制代码

  1. 本题考查对“缓存”的理解,很多人会被这个概念唬住,以为又是什么浏览器缓存啦,服务器缓存啦,甚至有人想到了redismemcached等工具,然后被吓得半死。其实没那么牛逼,你就是写一个变量,只要不销毁,都可以叫缓存。

答案:

</>复制代码

  1. var once = function(func) {
  2. var value,
  3. executed;
  4. return function() {
  5. var args = Array.prototype.slice.call(arguments);
  6. if (!executed) {
  7. executed = true;
  8. value = func.apply(this, args);
  9. return value;
  10. }
  11. return value;
  12. };
  13. };
  14. module.exports = once;

</>复制代码

  1. 通过设置一个executed的标记来判断该函数是否已经执行过了

21 - 请尝试完成一个类似"_.flatMap"的模块

</>复制代码

  1. 本题考查对map的理解。

答案:

</>复制代码

  1. var flatmap = function(array, iteratee) {
  2. return Array.prototype.concat.apply([], array.map(iteratee));
  3. };
  4. module.exports = flatmap;

</>复制代码

  1. 一个小技巧,对于二维数组,利用concat函数处理,代码更简洁

22 - 请尝试完成一个简单的middleware模块

</>复制代码

  1. 多少人写了很久的express,结果搞不清middleware是什么,怎么工作的,如何书写middleware,怎么使用middleware。这一切都源于对“中间件”这个概念的模糊,以及对express中“中间件”的实现原理的不解

答案:

</>复制代码

  1. var Middleware = function() {
  2. this.pool = [];
  3. };
  4. Middleware.prototype.use = function(cb) {
  5. this.pool.push(cb.bind(this));
  6. };
  7. Middleware.prototype.start = function(cb) {
  8. var _this = this;
  9. var pullOut = function() {
  10. if (_this.pool.length === 0) {
  11. return cb.call(_this);
  12. }
  13. _this.pool.shift()(pullOut);
  14. };
  15. pullOut();
  16. };
  17. module.exports = Middleware;

</>复制代码

  1. 关于middleware的详细介绍,可以看guide。

23 - 请尝试完成一个URL解析模块

</>复制代码

  1. 本题考查对URl的理解,各部分都是什么意思。在我们过往的经历中,经常发现候选人搞错一些概念,譬如:什么是query parameterprotocol指的是哪一段,domain又是哪一段,我们常说的hash/fragment是什么?分清楚各部分是什么,方便分解这道题

关于URL,你可能想看到如下图解:

答案:

</>复制代码

  1. var urlparser = function(url) {
  2. var result = /^(?:(https?):)//([.-w]+)(?:([/w]+))?(?:?([w=&]+))?$/.exec(url);
  3. var parsed = {protocol: result[1], host: result[2]};
  4. if (result[3]) {
  5. parsed.path = result[3];
  6. }
  7. if (result[4]) {
  8. parsed.query = result[4].split("&")
  9. .map((query) => query.split("="))
  10. .reduce((params, pairs) => (params[pairs[0]] = pairs[1], params), {});
  11. }
  12. return parsed;
  13. };
  14. module.exports = urlparser;

</>复制代码

  1. 这个答案我用了正则和mapreduce,略显臃肿。强烈欢迎更优解法

24 - 请尝试完成一个类似"_.throttle"的模块

</>复制代码

  1. 这又是个有故事的题,关于“节流阀”,是一种降低计算频率的处理。最常见的使用场景:当页面滚动时计算某一个值,相信如果你直白的在onScroll里写了计算行为后会发现,每移动一个像素都会触发一次计算,如果计算量还有一点大的话,卡不死你。这时候就用到了节流阀的技巧。关于“节流阀”更多详情,请看throttle

答案:

</>复制代码

  1. var throttle = function(func, wait) {
  2. var last,
  3. timer;
  4. return function() {
  5. var args = Array.prototype.slice.call(arguments);
  6. var _this = this,
  7. now = new Date().getTime();
  8. if (typeof last === "undefined") {
  9. last = now;
  10. return func.apply(_this, args);
  11. }
  12. clearTimeout(timer);
  13. if (now - last > wait) {
  14. last = new Date().getTime();
  15. return func.apply(_this, args);
  16. }
  17. timer = setTimeout(function() {
  18. last = new Date().getTime();
  19. func.apply(_this, args);
  20. }, wait + last - now);
  21. };
  22. };
  23. module.exports = throttle;
25 - 请尝试完成一个类似angularjs的依赖注入模块

</>复制代码

  1. 用过AngularJS的朋友肯定都见识到了“依赖注入”的威力(当然如果你是java转型的程序员,更应该有体会),依赖注入是一种解藕手段,我们在java中通常如是介绍:“依赖注入是实现IoC(控制反转)一种方式”。关于依赖注入,你也可以看手写依赖注入

答案:

</>复制代码

  1. var Di = function() {
  2. this.instanceStore = {};
  3. };
  4. Di.prototype.register = function(name, inst) {
  5. this.instanceStore[name] = inst;
  6. };
  7. Di.prototype.run = function(arr) {
  8. var _this = this,
  9. lastIndex = arr.length - 1;
  10. arr[lastIndex].apply(null,
  11. arr.slice(0, lastIndex)
  12. .map(function(name) {
  13. var Inst = _this.instanceStore[name];
  14. if (!Inst) {
  15. throw new Error("You are expecting a non-exist instance");
  16. }
  17. return typeof Inst === "function" ? new Inst() : Inst;
  18. }));
  19. };
  20. module.exports = Di;

</>复制代码

  1. 注意我在run实现里的typeof Inst === "function" ? new Inst() : Inst;使得如果注册的是一个构造函数,那么每次使用都会注入一个新的实例,这和AngularJS里使用单例的策略不同,这里留下一个问题,如果我希望使用单例策略,答案要做如何修改?

这是余下的15个题目,随时欢迎PR,欢迎指正,欢迎优化。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79879.html

相关文章

  • 开开心心几道JavaScript试题 - 01

    摘要:碰到这种面试官,你只有是个题霸,再加上眼缘够才能顺利入围。只要按照我题目的思路,甚至打出来测试用例看看,就能实现这个题目了。答案根据的,对答案做出修正。另我的答案绝不敢称最佳,随时欢迎优化修正。但了解总归是好的。 我们在长期的面试过程中,经历了种种苦不堪言,不诉苦感觉不过瘾(我尽量控制),然后主要聊聊常见JavaScript面试题的解法,以及面试注意事项 忆苦 面试第一苦,面试官的土 ...

    liujs 评论0 收藏0
  • JavaScript | 计时器参数剖析与真题

    摘要:学堂码匠计时器的第一个参数,包含几种不同的书写方法,可以是函数名,匿名函数,代码字符串,还有一些面试题当中会出现函数调用的书写方式。 HTML5学堂-码匠:计时器的第一个参数,包含几种不同的书写方法,可以是函数名,匿名函数,JS代码字符串,还有一些面试题当中会出现函数调用的书写方式。 那么,这些不同的书写方法分别表示什么呢?在计时器中出现的第一个参数,作用域又是在哪里创建的? 计时器第...

    Jenny_Tong 评论0 收藏0
  • JavaScript 关于this的几道试题及介绍

    摘要:对象方法中的当以对象里的方法的方式调用函数时,它们的是调用该函数的对象。注意,在何处或者如何定义调用函数完全不会影响到的行为。在这次执行期间,函数中的将指向。 原文链接 与其他语言相比,函数的this关键字在JavaScript中的行为略有不同。并且它在严格模式和非严格模式之间也有一些区别。 在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,在每次函数被...

    lifefriend_007 评论0 收藏0
  • 俩年的这五十篇技术博客,送给不忘初心的你。

    摘要:年开始的前三个学期有篇的产出。从技术角度来看,编程节奏加紧。十年文学,我等你。写给即将二十岁的你此你非彼你,写给一直伴我的你。巧合遇到你后的这段光阴,无比的充实与激情饱满。编程技术独立的挑战鼓励你。希望足以承担我爱你。 showImg(https://segmentfault.com/img/remote/1460000011417994); 这俩年通过体验博客园、常驻简书、甚至搭建静...

    tuantuan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<