周爱民老师关于面向对象的解说

322 阅读7分钟

前言

前段时间听了开课吧对于周爱民老师的一个访谈,真是收获巨大。对于面向对象的理解,对于函数式编程、对于promise这些都有着进一步的认识,在此跟大家分享一下。也推荐大家去B站搜索看一下开课吧的前端会客厅节目。

一.关于面向对象的解释

面向对象一开始其实只是面向对象,只是说到了对象。
根据oop之父的说法,那就是一个过程如果产生了一个与过程脱离了的东西,那这个东西就叫做对象,这个过程通常就是我们说的函数或者类。而在这个时候,其实完全没有谈及封装、继承、多态。
那么我们常说的面向对象程序设计其实说的是一个对象系统,是把很多个对象归类在一起的系统。既然是个系统就存在着系统原则,这些原则是用来描述系统如何组织这些对象的,而继承就是第一大原则。但是仍然会存在有些对象是个单独的对象,那么这些单独的对象以什么样的理由来放到系统中呢,那就是多态。多态分两种,一种是基于继承的,比如老虎既是动物,也是猫科动物。另一种多态是说某某某像什么,那他就是什么,这种多态是通过interface来实现的。有了这继承和多态两种东西,你发现你可以把所有的对象都归并到这个系统中。
还有一个就是封装,封装是最重要的东西,就是把所有那些不想让用户看到的内容封装在系统内,想看到的放在界面上。

二.js的封装设计

js没有私有对象,从一开始设计他的属性就都是public的,都是可以看见的。但是不同的对象之间属性是隔离的。所以js只做到了隔离。
总的来说,继承和多态不是对象必须的,封装才是必须的。而对于属性public而言,因为没有继承,只有封装,所以private根本不需要了。

大型程序设计对于面向对象非常热衷的原因是因为面向对象可以非常方便地组织对象系统。

三.js的继承

js一开始是没有继承的,只有最原始的封装。多态也有,但是多态是因为js本事就是一门动态语言,都是运行时决定的,所以多态是他天然的特性。从1.1开始就设计了原型继承,一直到es5都是。然后才出了类继承。继承有三种,原型继承、类继承、元类继承,js前面两种都实现了,元类继承是在ruby里面有出现。现在我们看到的所有类继承特性其实都是由原型继承来实现的,运行时还是只有原型,而写代码时可以有类,这也是比较奇葩的方式。

四.对于原型继承的理解

原型继承对于很多其他继承语言过来的开发者来说觉得很困惑,因为从继承的角度来看,哪个类到哪一层有哪些属性和方法都是一开始设计好的,怎么会出现改变了一个类的属性会影响到所有后续使用的情况呢。但是其实原型继承的实现恰恰是js的亮点,非常有优势,他带来了除了我们讲到的从系统构建经验发现占用内存少,构建方便系统组织灵活之外,他直接返朴归真地定义了对象到底是什么,即所谓的属性其实就是原型链上的动态访问。我查找一个属性,其实是查找这个对象和他所有的父级的类所有的原型属性的表的一个过程,这个过程特别好的地方在于他是跟动态语言和函数式语言是天生绑定的,属性的访问过程等于函数的调用过程,而动态是父类的属性可以动态地影响子类。所以js的原型继承其实是完整实现了动态语言和函数式的特性。所以他其实是很巧妙地实现了对象的集成,并且结合了语言特性,代价非常小,使用非常轻便。

前端里面通常使用继承的层次不会很多,基本上两层三层就能说明一个系统了,这种层级其实原型继承是不会有什么影响的,因为重复的属性名称也不会很多。但是在大型的复杂的对象系统里面,层次很多的话原型继承就比较麻烦了,容易混乱。同时,大型系统需要一个稳定的类设计,这样的库才会稳定。

结构化程序设计

早期结构程序设计包括数据结构,逻辑结构,组织的结构。后来出现了面向对象程序设计

函数式

全新的语言泛式 scheme 函数式语言就是函数运算求值得到结果。函数可以替代一切过程和运算结果,所以函数自然可以成为一门语言。函数式本身只是一个计算过程,与输入输出无关,不存储输入输出,所以输入输出要跟外部系统关联。

函数式语言的特点是:

  • 1.函数可以被传递
  • 2.函数等同于值
    等同于值的意思是他可以存储值,比如内部声明了一个变量,直接return,无论什么时候这个函数都等于这个值。第二个是保存了闭包,当函数被传递时,闭包也会跟着被传递。

动态函数式编程

promise

promise 的原理跟之前重写的差不多,基本一致。这个可以看一些面试题:js实现promise。

asyc

比如x = await getx();await 其实就是当执行到当前语句的时候,停下来等当前语句执行完毕,然后返回语句promise里面的那个值。停下来容易,就是直接把这个线程从list中拿掉就行了。但是怎么知道他ready了呢,其实也是一个promise.then 操作。当遇到await的时候,引擎自己会创建两个函数直接丢到当前语句的promise.then 里面,这两个函数的作用就是恢复之前的线程,并且将x添加进执行上下文。

并行执行程序是非顺序执行的,所以一定要抛去时间因素,不能追究谁先执行。

并行程序就是把时间因素抽掉。意思是promise的最终结果是多个需要执行的方法体的状态叠加,要把所有的情况都考虑到才可以做这个并行处理。

你永远不会知道promise 的then后面是具体什么时间执行。因为引擎会把这些then后面的函数放到一个列表,列表是只有一个的,所有的promise的then都放在里面。只有当主体程序全部执行完毕后才会去唤醒这个then里面的方法,并且因为这个list里面的的方法是互不依赖的,并且你不知道他被放在哪个CPU上执行,所以时间顺序上也是确定不了的,这就带来了promise的那个效果。

promise的伟大并不是只在于他目前实现的精妙,重点是在于思维上突破了以前的那种顺序执行思维,变成了时间无关性。