“全场最佳”(中高级)前端面试题(来自一个前端工程师)
2020-07-14 06:35
351 查看
前言
基于我面试别人和被别人面试的经验,我将整理一份清单。我面别人也好别人面我也好,都有一些总会被提及的问题。要记住,有些公司(比如Google)更加关注你是否可以做出高效的算法设计,所以如果你想去那儿工作,除了我下面列出的问题外,你还需要多加练习!
我会在这里添加或是更新这些问题的答案(欢迎你提出有建设性的需求!)
我将问题分为以下几个大类:
- 概念
- 编码
- 改错
- 系统设计
概念
请用清晰准确的语句解释如下名词(不需要编码):
- 什么是“大O”符号,它被用来表示什么?
- 什么是DOM?
- 什么是时间循环?
- 什么是闭包?
- 原型继承是怎样的,如何工作,它和普通的继承有什么区别?(这个问题没啥意义,但很多面试官都爱问)
this
如何工作,代表什么?- 什么是事件冒泡,它是如何工作的?(这也不是个好问题,同样的很多面试官很喜欢问。)
- 描述几种服务器和客户端之间的通信方式。描述一些网络协议是工作的(IP、TCP、http/S/2、UDP、RTC、DNS等)
- REST是什么, 为什么使用它?
- 网页加载的很慢,诊断原因且修复它。如何进行性能优化,什么时候应该进行性能优化?
- 你用过什么前端框架?它们各有什么优缺点?为什么我们要使用框架?框架能为我们解决什么问题?
编码
实现以下功能:
简单:
isPrime
- 返回true
或false
, 表示输入的数是否为质数:
isPrime(0) // false isPrime(1) // false isPrime(17) // true isPrime(10000000000000) // false
factorial
- 返回给定数的阶乘的值:
factorial(0) // 1 factorial(1) // 1 factorial(6) // 720
fib
-返回斐波那契数列的前n项的和(n为给定) 斐波那契数列.
fib(0) // 0 fib(1) // 1 fib(10) // 55 fib(20) // 6765
isSorted
- 返回true
或false
,表示给定的数组是否被排序过:
isSorted([]) // true isSorted([-Infinity, -5, 0, 3, 9]) // true isSorted([3, 9, -3, 10]) // false
filter
- 实现过滤器功能.
filter([1, 2, 3, 4], n => n < 3) // [1, 2]
reduce
- 实现reduce 函数.
reduce([1, 2, 3, 4], (a, b) => a + b, 0) // 10
reverse
- 反转给定字符串 (用已封装好的 reverse 是一个cheat,要自己实现).
reverse('') // '' reverse('abcdef') // 'fedcba'
indexOf
- 实现数组的 indexOf方法.
indexOf([1, 2, 3], 1) // 0 indexOf([1, 2, 3], 4) // -1
isPalindrome
- 返回true或false判断给定字符串是否是一个回文(palindrome)(大小写不敏感)
isPalindrome('') // true isPalindrome('abcdcba') // true isPalindrome('abcd') // false isPalindrome('A man a plan a canal Panama') // true
missing
- 一个数字1至n不重复且未排序过的数字组成的数组,从数字1至数字n选取出不重复且未排序过的数字组成数组(n为最大的数),调用方法后补全数组里缺失的数字。是否可以设计出时间复杂度为O(n)的算法?提示:有个聪明的方法供你使用。
missing([]) // undefined missing([1, 4, 3]) // 2 missing([2, 3, 4]) // 1 missing([5, 1, 4, 2]) // 3 missing([1, 2, 3, 4]) // undefined
isBalanced
- 用true
或false
表示给定的字符串的花括号是否平衡(一一对应)
isBalanced('}{') // false isBalanced('{{}') // false isBalanced('{}{}') // true isBalanced('foo { bar { baz } boo }') // true isBalanced('foo { bar { baz }') // false isBalanced('foo { bar } }') // false
中级:
fib2
- 实现像上面的fib
函数一样的功能,但是要能够算出数列中前50位以上的数的和。(小提示: 从内存中查询).
fib2(0) // 0 fib2(1) // 1 fib2(10) // 55 fib2(50) // 12586269025
isBalanced2
- 实现同上面的isBalanced
函数相同的功能,但是要支持三种类型的括号{},[],和()。带有交错括号的字符串应该返回false。
isBalanced2('(foo { bar (baz) [boo] })') // true isBalanced2('foo { bar { baz }') // false isBalanced2('foo { (bar [baz] } )') // false
uniq
- 选取一个由数字组成的数组,为其去重,返回去重后的数组。可以实现出时间复杂度为O(n)的算法吗?
uniq([]) // [] uniq([1, 4, 2, 2, 3, 4, 8]) // [1, 4, 2, 3, 8]
intersection
- 算出两个数组的交集(公共部分)。可以实现时间复杂度为O(M+N)(M和N为两个数组的长度)的方法吗?
intersection([1, 5, 4, 2], [8, 91, 4, 1, 3]) // [4, 1] intersection([1, 5, 4, 2], [7, 12]) // []
sort
-实现 sort 方法,用于排序元素为数字的数组, 且时间复杂度为O(N×log(N)).
sort([]) // [] sort([-4, 1, Infinity, 3, 3, 0]) // [-4, 0, 1, 3, 3, Infinity]
includes
- 判断给定的数字是否出现在给定的已排列好的数组中,返回true
或false
。是否能设计出时间复杂度为O(log(N))的算法?
includes([1, 3, 8, 10], 8) // true includes([1, 3, 8, 8, 15], 15) // true includes([1, 3, 8, 10, 15], 9) // false
assignDeep
- 仿照 Object.assign, 但是要深度合并对象。为了简单起见,可以假设对象只包含数字或是什么别的(而不是数组、函数等)。
assignDeep({ a: 1 }, {}) // { a: 1 } assignDeep({ a: 1 }, { a: 2 }) // { a: 2 } assignDeep({ a: 1 }, { a: { b: 2 } }) // { a: { b: 2 } } assignDeep({ a: { b: { c: 1 }}}, { a: { b: { d: 2 }}, e: 3 }) // { a: { b: { c: 1, d: 2 }}, e: 3 }
reduceAsync
- 仿照reduce 你在“简单”部分中完成了,但每个条目都必须在进行下一步之前被解决。
let a = () => Promise.resolve('a') let b = () => Promise.resolve('b') let c = () => new Promise(resolve => setTimeout(() => resolve('c'), 100)) await reduceAsync([a, b, c], (acc, value) => [...acc, value], []) // ['a', 'b', 'c'] await reduceAsync([a, c, b], (acc, value) => [...acc, value], ['d']) // ['d', 'a', 'c', 'b']
- 用
reduceAsync
来实现seq
。seq
使用一个可返回promise
的函数体内使用数组的函数,然后逐一的解决。
let a = () => Promise.resolve('a') let b = () => Promise.resolve('b') let c = () => Promise.resolve('c') await seq([a, b, c]) // ['a', 'b', 'c'] await seq([a, c, b]) // ['a', 'c', 'b']
困难:
注意:下面你要实现的数据结构问题,意不在让你记住它们,而只是希望你去查看给出的API,Google是怎么考虑且实现它们的,然后站在一个较高的角度去思考这些实现和其他数据结构相比如何。
permute
- 返回一个字符串数组,包含给定的字符串的所有的排列。
permute('') // [] permute('abc') // ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
debounce
- 实现 debounce 函数.
let a = () => console.log('foo') let b = debounce(a, 100) b() b() b() // only this call should invoke a()
- 实现一个 LinkedList 类,不用 JavaScript的built-in 数组 ([]). 你的链表需要支持两种方法,
add
和has
。
class LinkedList {...} let list = new LinkedList(1, 2, 3) list.add(4) // undefined list.add(5) // undefined list.has(1) // true list.has(4) // true list.has(6) // false
- 实现一个HashMap 类,不用JavaScript的built-in objects ({}) 方法或者是Maps方法。你需要提供一个
hash()
函数,传入一个字符串,返回一个数字(大多数情况下数字都是唯一的,有时候两个不同的字符串会返回一样的数字):
function hash (string) { return string .split('') .reduce((a, b) => ((a << 5) + a) + b.charCodeAt(0), 5381) }
你有的哈希表需要支持两种方法,
get和
set:
let map = new HashMap map.set('abc', 123) // undefined map.set('foo', 'bar') // undefined map.set('foo', 'baz') // undefined map.get('abc') // 123 map.get('foo') // 'baz' map.get('def') // undefined
- 实现一个BinarySearchTree(二叉搜索树)类,需要支持四种方法:
add
,has
,remove
,size
:
let tree = new BinarySearchTree tree.add(1, 2, 3, 4) tree.add(5) tree.has(2) // true tree.has(5) // true tree.remove(3) // undefined tree.size() // 4
- 实现一个BinaryTree(二叉树)类,广度优先搜索、中序排列、先序排列、后序遍历深度优先搜索功能。
let tree = new BinaryTree let fn = value => console.log(value) tree.add(1, 2, 3, 4) tree.bfs(fn) // undefined tree.inorder(fn) // undefined tree.preorder(fn) // undefined tree.postorder(fn) // undefined
改错
下面的每一个问题,先要弄明白为什么给出的代码块无法正常实现功能,然后想出解决方案,编写代码,正常实现功能:
- 我想要代码打印出:
“hey amy”
,但是它打印的是“hey arnold”
,为什么呢?
function greet(person) { if (person == { name: 'amy' }) { return 'hey amy' } else { return 'hey arnold' } } greet({ name: 'amy' })
2.我希望代码按顺序打印出数字
0,1,2,3,但是现在并不是这样的输出(这一度被认为是一个小bug,很多人喜欢在面试的时候提问为什么)
for (var i = 0; i < 4; i++) { setTimeout(() => console.log(i), 0) }
- 我希望代码打印出
“doggo”
,但是现在打出来是undefined
let dog = { name: 'doggo', sayName() { console.log(this.name) } } let sayName = dog.sayName sayName()
- 我想要我的
bark()
,但是我得到的确实error
,为什么呢?
function Dog(name) { this.name = name } Dog.bark = function() { console.log(this.name + ' says woof') } let fido = new Dog('fido') fido.bark()
- 为什么这个代码会返回这样结果?
function isBig(thing) { if (thing == 0 || thing == 1 || thing == 2) { return false } return true } isBig(1) // false isBig([2]) // false isBig([3]) // true
系统设计
- 来聊聊看,如果想要做一个完整的自动补全的小程序(widget)。用户可以在其中输入文字,并从服务器得到返回结果。
- 你会如何设计一个支持以下功能的前端页面: 从后台API获取数据
- 以树形渲染结果(每个对象可以有父/子,而不是一个平铺的列表)
- 支持
checkbox, radio button, icon
以及普通的列表项-列表项从很多的表单中得到
- 谈谈如何实现Twitter的全栈构建。
- 如何获取并渲染每条推特消息?
- 当有新的推文来了你该如何渲染?你如何知道啥时候来了新的推文?
- 你该如何设计搜索推文?如何按作者搜索推文?聊聊你的数据库、后台以及API设计。
推荐 :
- 020 持续更新,精品小圈子每日都有新内容,干货浓度极高。
- 结实人脉、讨论技术 你想要的这里都有!
- 抢先入群,跑赢同龄人!(入群无需任何费用)
- 点击此处,与前端开发大牛一起交流学习
申请即送:
- BAT大厂面试题、独家面试工具包,
- 资料免费领取,包括 各类面试题以及答案整理,各大厂面试真题分享!
相关文章推荐
- 一个前端工程师的面试经历
- web前端高级工程师,面试题
- 中高级前端开发高频面试题
- 前端开发工程师面试题
- 网上搜索整理的前端开发工程师面试题附答案
- 如何称为一个优秀的前端工程师?
- 怎样成长为一个优秀的 Web 前端开发工程师?
- 做为一个前端工程师,是往node方面转,还是往HTML5方面转
- 阿里云前端周刊 - 第 29 期 RESTful API 设计最佳实践_项目资源的URL应该如何设计?用名词复数还是用名词单数?一个资源需要多少个URL?
- 刚看到一个前端面试题, 左边固定,右边自适应, 就根据自己想的自己写了下试试
- 个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能
- 做为一个前端工程师,是往node方面转,还是往HTML5方面转
- 如何做一个好的前端重构工程师
- 怎样成长为一个优秀的 Web 前端开发工程师?
- 如何做一个好的前端重构工程师
- github上比较有名的一个前端面试题,随便做做(6)
- 前端面试题——给一个div加上10px的圆角
- 前端面试题--原生脚本代码,实现点击事件,动态添加或者删除一个class类名
- 最新前端开发工程师面试题——HTML部分
- 中高级前端开发高频面试题