什么是OOP
OOP ,即面向对象编程,是基于原型,通过封装、继承、多态组织代码的面向对象编程范式
JS的OOP本质
通过原型链实现对象间的属性 / 方法共享与委托
何为原型
原型(prototype
)是函数的一个属性 ,它是一个对象,用于存储所有实例共享的属性和方法;实例对象通过 __proto__
指向该原型。每个实例对象都有其对应的唯一原型,一个原型可对应很多实例对象
原型链
原型链是实例对象与原型对象之间的链式关联(实例 → 构造函数原型 → 父构造函数原型 → ... → null)。通过原型链可共享向上查找并共享父原型的属性和方法

如上图所示:
- 所有对象的原型链最终都会指向
Object.prototype
(除Object.prototype
自身,其__proto__
为null
),并以null结束 - 当外部访问一个属性/方法时,先从当前的原型查找,如果找到则用当前原型即可,如果未找到则沿着原型链向上进行查找,找到直接拿过来用,实现"共享"
Notice:与Java的类实现本质不同,Java是通过父类复制属性和方法到子类中实现继承连接,属于"向下共用";而JS是通过原型链来实现对象之间的连接,属于"向上共用"
如何实现对象连接原型
构造函数
步骤:
- 在子构造函数中通过
Parent.call(this, 参数)
调用父构造函数,目的是继承父构造函数中的实例属性 (而非 "实现 this 的指向"),this
本身已指向子实例,call
的作用是绑定父构造函数的this
为子实例。 - 填写相应的属性和方法
- 连接原型:连接父原型和子原型------子类构造函数.
prototype
=Object.creat
(父类构造函数.prototype
) - 将子构造函数原型的
constructor
重置为自身 - 通过
new
关键字创建一个实例对象
Notice:
- 若想在子实例中新增一个新方法,则最好是在其原型上增加,好处是更加简洁,便于后续的实例也同样添加其方法
- 获得原型的方法:
实例.__proto__
指向原型(英文的双下划线),即构造函数.prototype === 实例.__proto__
- 在方法内容书写的最后一般都
return this
便于实现方法链
ES6+class
步骤:
- 类比Java的类的实现模板,创建一个
class
,并用extends
创建原型链 - 在构造函数
constructor
中使用super
来实现this
的指向为子类实例 - 然后再内部实现属性和方法 、
Notice:
set/get
方法
set
方法:当方法为set 函数名 ...
时分两种情况,当函数名与函数内部调用的属性名均不相等时,可直接用;反之,需要将类内所有调用的属性名都适当改变(一般使用假封装),避免无限迭代。使用set
方法可以实现对值得验证和处理get
方法:当方法为get 函数名 ...
时可直接用实例.函数名
调用该方法(一般函数名就是属性名)
- 静态方法:在最前面添加
static
,该方法只能用类而不能用实例调用
OOP特性
封装
封装的目的是为了实现数据保护,避免直接被外部直接访问获取
真封装
共有属性/方法,直接正常写
私有属性/方法,在前面添加"#",若在构造函数中赋值私有属性,需要在类内部先声明
假封装
在属性/方法名前面添加"_"
_
只是命名约定 (表示 "建议外部不要访问"),但无法真正阻止外部访问(仍可通过 obj._prop
读写),不属于 "封装",仅为开发者之间的约定。
继承
继承:实例属性、原型链+方法
构造函数
具体体现在"如何实现对象连接原型------构造函数"中的call
、Object.creat
以及重置constructor
call
用于继承实例属性Object.create
用于连接原型链(继承原型方法) ,两者结合才是完整的继承实现,缺一不可。
ES6+class
具体体现在"如何实现对象连接原型------ES6+class"中的super
、extends
super()
负责实例层面的继承(获取父类实例属性)。extends
负责原型链层面的继承(共享原型方法);
Object.creat()
具体使用在"构造函数------步骤------连接原型"中
Object.create(proto)
的核心作用是创建一个以 proto
为原型的新对象,其主要用途是实现原型继承
多态
在JS中体现为原型链上的方法重写实现,即同一方法在不同对象上调用时表现出不同行为,以及动态类型检查 ,都体现并实现了同一接口,不同实现
最后
前端开发之路任重而道远,在未来仍有很多知识需要学习,小编也是一个初学者,让我们一起加油!如果这篇文章能帮到你的话,荣幸之至;如果有错误的话并指出来的话,小编将不胜感激。