每一个JavaScript开发者都应该知道的10道面试题
这里有一些问题将帮助你了解其真正的奥妙所在:
1、你能说出对JavaScript应用开发人员非常重要的两种编程范式吗?
答:
JavaScript是一门多范式语言, 支持命令式/过程式编程以及OOP(面向对象编程)和函数式编程。JavaScript使用原型继承来实现OOP。
面试官非常高兴听到这些:
·原型继承(或:原型,OLOO(对象链接到其它对象)模式)。
·函数式编程(或:闭包,First-class Function,lambda)。
警告:
·不知道什么是范式,没有提及原型对象或函数式编程。
了解很多其它:
·TheTwo Pillars of JavaScript Part 1 — PrototypalOO.
·TheTwo Pillars of JavaScript Part 2 — FunctionalProgramming.
2、什么是函数式编程?
答:
函数式编程是一种编程范式。在函数式编程语言中,函数是第一类的对象。也就是说,函数不依赖于不论什么其它的对象而能够独立存在,而在面向对象的语言中,函数 ( 方法 ) 是依附于对象的,属于对象的一部分。这一点决定了函数在函数式语言中的一些特别的性质,比方作为传出/传入參数,作为一个普通的变量等。Lisp是最早支持函数式编程的语言。
函数式编程是JavaScript的一个基本概念(JavaScript的两大支柱之中的一个)。几种常见的功能特性在ES5后被加入到JavaScript中。
面试官非常高兴听到这些:
·纯函数/函数纯度。
·避免边界效应。
·简单的函数组合。
·函数式语言的样例:Lisp,ML,Haskell,Erlang,Clojure。Elm。F Sharp,OCaml等等。
·提到支持函数式编程功能的特性:第一类函数,高阶函数,函数作为參数/值。
警告:
·没有提及纯函数/避免边界效应。
·不能说出函数式编程语言的样例。
·不了解JavaScript支持函数式编程的特性。
了解很多其它:
·TheTwo Pillars of JavaScript Part 2.
·ProfessorFrisby’s Mostly Adequate Guide to Functional Programming.
3、类继承和原型继承之间的差别?
答:
类继承:实例继承类。并创建子类之间的关系:类层次分类。
实例通过构造函数实例化。通经常使用“new”keyword。类继承可用也可不用从ES6的“class”keyword。
原型继承:实例直接从其它对象继承。实例通常使用工厂函数或“Object.create()”来初始化。实例能够由很多不同的对象组成的。同意轻松地选择继承。
在JavaScript中,原型继承比类继承更灵活、简单。
面试官非常高兴听到这些:
·类:类继承多了会产生紧耦合,层次结构/分类。
·原型:提到衔接继承,原型托付,函数继承,对象组成。
警告:
·一定要偏爱原型继承和组合胜过类继承。
了解很多其它:
·TheTwo Pillars of JavaScript Part 1 — PrototypalOO.
·CommonMisconceptions About Inheritance in JavaScript.
4、函数式编程与面向对象编程相比有什么长处和缺点?
答:
面向对象长处:我们非常easy理解对象的基本概念,easy理解的方法调用的含义。
OOP倾向于使用命令式的风格,而不是声明的风格,倒像是一个直接让计算机使用的指令集。
面向对象缺点:面向对象通常依赖于共享状态。对象和行为通常附着在同样的实体,这使得它能够被随意多个函数随机訪问,且这样的訪问顺序是非确定性的,这可能导致不希望看到的行为,比如竞争条件。
函数式编程长处:使用函数范式,程序猿能够避免不论什么共享状态或边界效应,从而消除由多个函数竞争同样的资源带来的错误。
相比面向对象编程,因为自由点方式(又名默契/隐性编程)的可用性这一特性,对于更一般的可重用代码来说,函数往往能够从根本上简化和方便地被重构。
函数式编程倾向于声明性的风格,它不须要用算法来明白的指出每一步该怎么做(命令式编程:命令“机器”怎样去做事情(how),这样无论你想要的是什么(what)。它都会依照你的命令实现。
),而是告诉“机器”你想要的是什么(what),让机器想出怎样去做(how)。这给重构和性能优化留下了巨大的空间。甚至同意你以很少却更高效的代码来替换整个算法。
(比如。记忆化,或使用惰性求值取代急切求值。
)
计算这使得纯函数的使用也非常easy扩展到多个处理器,或在分布式计算集群。而不必操心线程资源冲突,竞争条件等等。
函数式编程缺点:过度开发函数式编程的功能,如常常使用自由点方式以及大规模组合可能会降低代码可读性,由于生成的代码往往比較抽象,简洁。
比起函数式编程。很多其它的人熟悉面向对象和命令式编程 。所以新增加的成员可能在一些习惯使用方法上会造成混淆。
函数式编程比面向对象编程的学习曲线更加陡峭。由于面向对象的广泛普及使得面向对象的语言和学习材料变得更加熟络,而函数式编程的语言往往更加学术和正式。函数式编程概念常常使用习惯用语和符号的演算,代数和范畴论等来描写叙述,全部这一切都须要在这些领域的现有知识基础来理解。
面试官非常高兴听到这些:
·提到共享状态。不同的事情争夺同样的资源等等麻烦...
·意识到函数式编程的能力,从根本上简化了很多应用。
·意识到函数式编程和面向对象编程在学习曲线上的不同。
·表达边界效应以及它怎样影响程序的可维护性。
·认识到一个功能强大的代码库会有一个陡峭的学习曲线。
·认识到一个高度面向对象的代码库会是非常难以改变。非常脆弱,相比于FP代码库。
警告:
·无法列出的一种风格或其它风格的缺点 - 不论什么人都经历了两种风格应该已经碰到了一些限制。
了解很多其它:
·TheTwo Pillars of JavaScript Part 1 — PrototypalOO.
·TheTwo Pillars of JavaScript Part 2 — FunctionalProgramming.
5、何时选择类继承是正确的?
答:这是一个有趣的问题。答案是永远不会。多年来我一直在发出这一挑战,我听过的答案分为几种常见的误解。更常见的则是遭遇沉默。
“If afeature is sometimes useful and sometimes dangerous and if there is a betteroption then always use the better option.” ~ Douglas Crockford
面试官非常高兴听到这些:
·非常少。差点儿没有,或者永远。
·“比起类继承我更喜欢对象组合”。
警告:
·其它答案
·“React Components”——不,类继承的缺陷并不因一个新框架的出现和拥抱“class”这个keyword而改变。
你并不须要为了使用React而使用“class”。这个回答揭示了你对“class”和React的误解。
了解很多其它:
·TheTwo Pillars of JavaScript Part 1 — PrototypalOO.
·JS Objects — Inherited aMess.
6、何时选择原型继承是正确的?
答:
原型继承有下面几种类型:
·托付(即原型链)。
·衔接(Mixins,“Object.assign()”)。
·函数(不要和函数式编程混淆。函数用于创建一个私有状态/封装的闭包)。
每种类型的原型继承都具有自己使用情况,但全部这些在它们的组合能力上相同实用,都创建has-a或uses-a或can-do关系。而类继承创建的是is-a关系。
面试官非常高兴听到这些:
·在模块或函数式编程不提供明显的解决方式的情况下。
·当你须要编写来自多个来源的对象时。
·当你须要继承时。
警告:
·对什么时候使用原型搞不清楚。
·不认识Mixins或“Object.assign()”。
了解很多其它:
·“ProgrammingJavaScript Applications”: Prototypes section.
7、“比起类继承更喜欢对象组合”是什么意思?
答:这是从“设计模式:可复用面向对象软件的基础”书中的引用。这意味着代码重用应由装配更小单位的功能到新对象来实现,而不是继承类和创建对象分类来实现。
换句话说就是:用has-a或uses-a或can-do关系来取代is-a关系。
面试官非常高兴听到这些:
·避免类层次结构。
·避免脆弱的基类问题。
·避免紧耦合。
·避免僵化的分类(对新的使用情况来说,强迫is-a关系终于是错误的)。
·避免大猩猩的香蕉问题(“你想要的是一个香蕉,但你得到的是一个大猩猩拿着香蕉。整个丛林”)。
·使代码更灵活。
警告:
·没有提到上述的不论什么点。
·不可以清晰地表达组成和类继承的差别,或组合物的长处。
了解很多其它:
·composition overinheritance及实例分析
8、什么是双向数据绑定和单向数据流,以及它们之间的差别?
答:
双向数据绑定意味着UI字段动态绑定到模型数据上,当一个UI字段变化,它的模型数据将改变。反之亦然。
单向数据流意味着该模型是唯一的来源。仅仅有模型才有改变应用程序状态的权力。其效果是,数据总是在一个单一的方向流动,这使得它更easy理解。
单向数据流是确定性的。而双向绑定可引起副作用而令人更难把握和理解。
面试官非常高兴听到这些:
·React是单向数据流的新的典型样例。因此提到React是一个好消息,当然你也能够使用ReactLink在React中实现双向绑定。Cycle.js是单向数据流的还有一种流行的实现。
·Angular是一种使用双向绑定的流行框架。
警告:
·不了解这两种是什么东西。无法表达它们之间的差异。
了解很多其它:
9、总体架构与微服务架构各自的利弊?
答:
总体架构意味着你的应用程序被写成一个由代码拼成的总体,其组件被设计成协同工作,共享同样的存储空间和资源。
微服务架构意味着你的应用程序是由大量的可以在自己的内存空间中执行,相互独立缩放。跨越潜在的多个独立的机器。
总体架构长处:大多数应用程序通常有大量的横切关注点。如日志记录。速率限制。审计跟踪和DOS防护等安全功能。
当一切都执行在同一个应用程序,它非常easy连接到这些横切关注点的组件。还有一个长处就是共享内存訪问比进程间通信(IPC)更快。
总体架构缺点:随着应用服务不断更新,其往往会更加紧密地耦合和纠缠在一起。因此非常难有目的地分离服务,如独立的缩放或代码可维护性。
总体架构也非常难理解,由于一个特定的服务或控制器可能有依赖,副作用和不可预知因素,这是不明显的。
微服务架构长处:微服务架构有着更好的组织,由于每一个微服务具有很详细的工作。而且不涉及其他组分的作业。
分开的服务也更easy又一次组合和又一次配置。以满足不同的应用程序的目的(比如,服务于Webclient和公共API)。他们还能够有性能优势,这取决于他们是怎样组织的,由于它能够隔离热服务和缩放它们独立于应用程序的其他部分。
微服务架构缺点:当你正在构建一个新的微服务架构,你可能会发现大量的交叉问题,这在设计时是你没有预料到。而一种总体架构应用程序能够建立共享的帮助者或中间件来毫不费力地处理横切关注。
在微服务架构中,你要么为每一个横切关注点产生单独模块的开销。或在还有一个服务层中封装横切关注点,以使全部业务都通过。
最后,即使总体架构倾向于通过一个外部服务层来解决交叉关注的问题,但这有可能延误了这项工作的费用,直到该项目更为成熟。
微服务经常被部署在自己的虚拟机或容器中,导致虚拟机放牧式工作的激增。这些任务经常常使用容器管理工具来做自己主动化。
面试官非常高兴听到这些:
·对微服务架构的积极态度,虽然较高的初始成本VS 总体架构应用程序。意识到从长远来看微服务往往运作性和伸缩性更好。
·自己有在微服务架构和总体架构方面的实践。微服务架构中的服务在代码级别是相互独立的,在一開始就比总体架构应用easy捆绑在一起。微服务架构管理成本能够被延迟,直到它变得更切合实际的支付价钱。
警告:
·不知道总体架构和微服务架构之间的差异。
·不了解或不切实际的知道有关微服务架构的额外开销。
·不了解IPC和微服务网络通信的所造成的额外性能开销。
·关于微服务的弊端太消极。无法说出在时机成熟时将总体架构分裂成微服务的方式。
·低估了独立可伸缩微服务的优势。
10、什么是异步编程,为什么它在JavaScript中非常重要?
答:
同步编程意味着,限制的条件和功能调用,代码依次从顶至底执行时。堵塞在长期执行的任务,如网络请求和磁盘I/O。
异步编程意味着发动机在事件循环执行。
当须要堵塞操作,请求被启动。而且代码不断不会堵塞的结果执行。
当响应准备就绪,中断发射。这将导致一个事件处理程序来执行。当中,控制流继续。以这样的方式。单个程序线程可处理很多并发操作。
用户界面本质上是异步的。并花费大量的时间等待用户输入中断事件循环和触发事件处理程序。
节点本质上是异步的。这意味着server工作在大致同样的方式。在等待一个网络请求的环路。并在第1个被处理时能够接受很多其它到来的请求。
这在JavaScript中是很重要的,由于它很自然地适合用户接口代码。并对server性能很故意。
面试官非常高兴听到这些:
·了解堵塞和性能的含义。
·了解事件处理,以及它对用户界面代码的重要性。
警告:
·不熟悉异步或同步术语。
·无法说出性能的含义或异步代码与UI代码之间的关系。
了解很多其它:
·JavaScript执行机制具体解释:再谈Event Loop
结论
面试结束。坚持高水平的主题。假设你们能回答这些问题,这通常意味着你们有足够的编程经验在几个星期内掌握语言的怪癖和语法。即使你们没有非常多的JavaScript编程经验。
作为面试官。请不要用基础知识的不扎实来取消面试者的资格。那些都太easy学了。
你真正须要知道的是,“面试者是否了解怎样把一个应用程序拼凑在一起吗?”