什么是面向过程
分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
是一种以过程为中心的编程思想 代码没有任何封装,按照编码的逻辑 自上而下 平铺直叙。
面向过程是一种自顶而下的编程思想,将要实现的功能划分为小的模块,再将小的模块继续细分,当所有模块都写完,功能也就实现。
优点
1.运行效率高,因为与 CPU 的工作方式接近,CPU 就是按照顺序来一步一步执行的。
2.编程效率高,不需要对功能进行复杂的抽象,直接进行划分就好,只不过模块划分的粒度和划分原则需要把控好,这也是架构师的重要职责之一
缺点
1.程序扩展性和灵活性比较差,如果功能有改动,对程序会进行较大的改动,而且由于很多地方会改动,不能快速适应需求的变化
2.数据存在很多工程共享数据,安全性不好
什么是面向对象
- 是把构成问题的事务分解成各个对象,每个对象都有自己独立的属性和行为, 对象可以将整个问题事务进行分工, 不同的对象做不同的事情。
- 是一类以对象作为基本程序结构单位的程序设计语言,指用于描述的设计是以对象为核心。
面向对象的编程思想是先根据要实现的功能,抽象出对象,或者说类,然后赋予对象相应的数据和操作,功能的实现依靠对象的方法调用。
- 优点
- 1.安全,面向对象的封装特性会将数据进行隐藏,保证数据的安全。
- 2.扩展性好,需求的更改会体现在某个对象的或某些对象的修改上,因此只需要做局部的修改就好,不会对全局造成影响。
- 3.复用,代码冗余小。由于继承的特性,代码量得到了很大的缩减,重写的特性又保证了多态,即灵活性
- 缺点
- 1.抽象相对复杂,不如直接写功能模块方便
概念
面向对象也即是 OOP,Object Oriented Programming,是计算机的一种编程架构,OOP 的基本原则是计算机是由子程序作用的单个或者多个对象组合而成,包含属性和方法的对象是类的实例,但是 JavaScript 中没有类 class 的概念(但是 es6 中新增的 class 的概念),而是直接使用对象来实现编程。
特征:
- 封装
- 继承
- 多态
封装:
封装的主要目的就是为了隐藏数据信息,包括属性和方法的私有化。封装可以使对象内部的变化对其他对象而言是透明的,对象只对自己的行为负责。对象之间通过暴露 API 接口来进行通信,其他对象和用户不需要关心 API 的实现细节,是对象之间的耦合变松散。(解耦)
公有属性,公有方法:属性在构造函数中声明,方法定义在原型上
私有属性,私有方法 : js 中没有私有属性的概念我们一般使用_约定的形式表达私有概念
静态属性,静态方法:我们一般吧静态属性静态方法添加到类上直接通过类来调用
1 | function User(name, age, id) { |
重载:
多态是同一个行为具有多个不同表现形式或形态的能力,简单点就是一个 api 方法有多种用途,类似 jquery 中,不同的方法传递参数个数,参数类型等,都可以实现不同的效果
继承
既然要实现继承,那么首先我们得有一个父类,代码如下:
1 | // 定义一个动物类 |
原型链继承 (**)
利用 js 原型链的特点将子类的原型等于父类的实例,那么子类在原型链访问过程中就可以访问到父类的属性和方法,问题,多个实例共享一个原型, 如果父类中有引用类型数据的话,多个子类其中一个改变其他的都会改变,因为 js 引用类型的问题会有属性共享的问题
核心: 将父类的实例作为子类的原型
1 | function Cat() {} |
特点:
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 父类新增原型方法/原型属性,子类都能访问到
- 简单,易于实现
缺点:
- 要想为子类新增属性和方法,必须要在 new Animal()这样的语句之后执行,不能放到构造器中
- 无法实现多继承
- 来自原型对象的所有属性被所有实例共享(
来自原型对象的引用属性是所有实例共享的)(详细请看附录代码: 示例 1) - 创建子类实例时,无法向父类构造函数传参
构造函数继承
相当于吧父类当成一个函数在子类中运行,并且改变 this 为子类实例,这样就相当于拷贝了父类中构造函数中的属性和方法,实现构造函数继承,但是无法继承原型中的方法和属性
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
1 | function Cat(name) { |
特点:
- 解决了 1 中,子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call 多个父类对象)
缺点:
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
实例继承
核心:为父类实例添加新特性,作为子类实例返回
1 | function Cat(name) { |
特点:
- 不限制调用方式,不管是 new 子类()还是子类(),返回的对象具有相同的效果
缺点:
- 实例是父类的实例,不是子类的实例
- 不支持多继承
拷贝继承
1 | function Cat(name) { |
特点:
- 支持多继承
缺点:
- 效率较低,内存占用高(因为要拷贝父类的属性、方法)
- 无法获取父类不可枚举的方法(不可枚举方法,不能使用 for in 访问到)
- 无法获取父类的静态属性、静态方法
组合继承
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
1 | function Cat(name) { |
特点:
- 弥补了方式 2 的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
- 既是子类的实例,也是父类的实例
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点:
- 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
寄生组合继承
核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
1 | function Cat(name) { |
特点:
- 堪称完美
缺点:
- 实现较为复杂
测试一下
1 | function Animal (name) { |
- Post link: https://blog.gaocaipeng.com/2020/03/12/vu6efn/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.