1. 请说出对JS开发者有用的两种编程范式?
JS 是一种多范式编程语言,支持声明式/过程式编程和面向对象编程、函数式编程。
JS通过原型继承实现OOP。
正解
-
原型继承或对象链接
-
函数式编程,包括: 闭包、一等函数、lambda表达式
错解
- 不知道编程范式,也不知道原型继承或者函数式编程
2. 什么是函数式编程?
函数式编程通过组合数学函数来组织程序,会避免共享状态和可变数据。
Lisp语言,创建于1958年,是第一个支持函数式编程的语言,主要来源于lambda算式。
Lisp和Lisp家族语言至今仍在广泛使用。
函数式编程是JS的基础概念,ES5版本JS已经加入很多函数工具。
正解
-
纯函数/函数纯净度
-
规避副作用
-
简单函数组合
-
示例函数式语言: Lisp,ML,Haskell, Erlang, Clojure, Elm, F Sharp, OCaml等等
-
知道常见支持函数式编程的特性,如: 一等函数,高阶函数,函数入参或返回值
错解
-
不知道纯函数或副作用
-
不知道函数式示例语言
-
不知道哪些JS功能支持函数式编程
3. 类继承和原型继承的区别?
类继承是指通过实例继承类,类似蓝图-类的描述。
创建具有子父类关系,分层类。
实例通过new关键字调用构造函数进行类实例化。
类继承可以不用ESclass
关键字实现。
原型继承是指实例直接指向某些对象,实例通过调用工厂函数或Object.create
方法生成。
实例可以从多个不同对象组合而来,允许简单选择性继承。
JS中原型继承比类继承更灵活
正解
-
类用于创建高耦合或分层结构
-
知道连续性继承,原型代理,函数继承,对象组合
错解
- 不知道优先选择原型继承和组合
4. 函数式编程和面向对象编程的优劣
OOP优点:
- 对象概念理解简单,方法调用解释简单,OOP倾向于使用命令式而不是声明式,读起来像是一串计算机认识的直接指令。
OOP缺点:
- OOP依赖共享状态,对象和行为都合在相同实体中,对象内部多个函数会随机访问实体,可能会导致不好的结果,如:竞态条件。
FP优点:
-
开发者使用函数式编程,可以避免共享状态或副作用,会减少多个函数访问相同资源引起的BUG。
-
由于引入自由点式编程,函数趋向于更加简单,和OOP相比更容易重新组合生成可重用的代码。
-
FP趋于使用声明式和指称式,不会指定操作的每一步指令。相反,FP集中于执行结果,执行过程交给更底层函数。
-
这样可以给重构和性能优化提供巨大空间,甚至可以用更高效函数替换整个逻辑,代码层面改动很少。
-
使用纯函数进行计算也很容易扩展至多个处理器或者分布式计算集群中。
FP缺点:
-
过度使用FP的特性,像自由范式和大型组合会潜在降低代码可读性,因为结果代码会变得十分抽象简洁。
-
大部分开发者熟悉OOP和命令式编程,所以函数式编程中通用叫法可能会让新成员很迷惑。
-
FP比OOP有着更陡峭的学习曲线,因为OOP的流行使得OOP学习材料变得很普遍,而FP趋于更加学术和正式。
-
FP的很多概念取自lambda运算,代数和分类理论,需要开发者在这些领域有一定的知识基础才能理解。
正解
-
提到共享状态,多个函数竞争相同资源
-
意识到FP能够极大简化很多应用
-
意识到学习曲线的不同
-
知道副作用和如何应用程序可维护性
-
高度函数式代码会导致陡峭学习曲线
-
知道高度OOP代码比相同的FP代码会更难维护
-
知道不可变可以提升程序访问度,形成可延伸的程序状态历史,允许无尽的重做、回退和时间线调试等等。
-
不可变可以在任何范式中实现,但共享状态对象的增加会让OOP实现变得复杂。
错解
- 不知道两者优缺点
5. 类继承的合适场景?
答案是否或几乎不用,显然不包含一层的情况,多层类体系是一种反模式。
如果功能有时有用,有时危险,如果有更好的选择,那就一直用最佳方案。-JS大牛-Douglas Crockford
-
几乎不用或不用
-
有时会用在单一层级,直接基于框架的类,像
React.Component
-
对象组合优先
6. 原型继承的合适场景?
原型继承实现不只一种:
代理,如,原型链
合并,如, 混合 Object.assign
函数型,创建维护私有状态或封装的闭包
每种类型的原型继承都有其本身使用场景, 但所有都支持十分有用的组合功能,会创建存在有A或使用A、能执行A这些关系,相反,类继承会创建是否A。
正解:
-
适用于模块化和函数式编程无法提供解决方案的场景
-
当需要从多个来源组合对象
-
任何需要继承的场景
错解:
-
不知道何时使用原型
-
不知道混合和
Object.assign
7. 如何理解优先选择对象组合而不是类继承
这句话引自设计模式:可重用面向对象软件方法
一书,
它的含义是代码重用应该通过组装微型功能单元成新对象而不是继承并创建类层次。
正解:
-
避免类层级
-
避免脆弱基类问题
-
避免死板的层级
-
避免大猩猩香蕉问题
-
灵活设计代码
错解:
-
不知道上面的问题
-
无法表述清楚组合和类继承的区别或组合的优势
8. 什么是双向绑定和单向数据流,他们的异同?
双向数据绑定意味着UI界面字段会动态绑定到模型数据,当界面字段变化时,模型数据也会变化,反之亦然。
单向数据流意味着模型成为单一来源。
UI变化向模型传递触发用户动作的消息, 例如,React中的store。
只有模型有权限改变应用状态。
数据总是单向流动,让人很容易理解。
单向数据流是明确的,然后双向数据绑定会带来副作用,导致复杂和难以理解。
正解:
-
React是单向数据流的标准案例,cycle.js是另外一个流行的单向数据流实现库。
-
angular采用双向绑定,也很流行。
错解:
- 不了解两种数据流,也不能表述清楚区别。
9. 什么是异步编程? 为什么在JS如此重要?
同步编程意味着拦截条件和函数调用,代码自上而下线性执行,网络请求和磁盘IO会等耗时任务会被阻塞。
异步编程意味着,引擎以事件循环方式运行,当需要进行阻塞操作时,请求发出,代码继续执行无需阻塞结果。
当响应可用时,中断消息触发,调用对应的事件处理器,传递结果,整个控制流会继续进行。
这种情形下,单一程序线程可以处理处理多个并发操作。
用户交互本身就是异步,需要花大量事件等待用户输入,然后打断事件循环,触发事件处理。
Nodejs默认异步,服务端也是这样工作,在循环中等待网络请求,第一个请求处理时也继续接
收更多新请求。
异步在JS中很重要,因为天生适合用户交互代码,对于服务端性能也有用。
正解:
-
理解什么是阻塞和性能影响
-
理解事件处理及其对于界面代码的重要性
错解:
-
不了解同步和异步术语
-
不能表述性能影响或异步代码和UI代码的关系
译者注
-
原文有删减,因译者水平有限,如有错误,欢迎留言指正交流
网友评论