原型太抽象了,能不能讲个生活小场景帮我理解?当然可以,附上图解更好理解!
1. 什么是原型
不讲理论,先讲一个生活场景来帮助理解
你所在的公司,会给你提供一些
公共资产
,比如办公桌椅、公共饮水间等,这些都是每个人都可以使用的(不管你是开发人员,还是销售人员,都可以用)。当然,你如果觉得公司的桌椅不舒服,你可以自己买
自己用;但是你如果没有自己的桌椅的话,第一想到的是会先向公司要
,公司如果有,就会给你提供;公司如果没有,那对不起,你只能站着办公了~
聊完上面的场景,我想把上面提到的一些关键点,转换为下面这张图
如果我再把上面的图,用 JS 中的类的概念转换为下面的图(可能比喻并不恰当,但可以帮助你理解原型的概念和作用)
- 图中有一个
Person
类,其中包含了自有属性prop
- 通过
Person
类,实例化出多个对象
,如 “销售人员”、“开发人员”
看完上面的图,来一波小总结~(附图如下)
- 原型对象:图中的
公司
,是 Person 类的原型对象,也是实例化后的 “销售人员”、“开发人员” 的原型对象 - 显示原型 & 隐式原型
- Person 通过
prototype
指向 “公司”,prototype 称为 显示原型 - 实例对象通过
__proto__
指向 “公司”,__proto__
称为 隐式原型
- Person 通过
- 原型特点
- 如果自身有属性,就直接用该自有属性;若自身无该属性,则会沿着原型对象继续查找,若原型对象身上有,则直接用原型对象的(也就是销售人员没自己的桌椅时,可以找公司要)
Person.prototype === 销售人员.__proto__
,这个等式证明,他们都指向同一个原型对象- 原型对象的
constructor
指向构造函数(该示例中,指回到了Person
类,即 Person 的构造函数
) - 原型最终都会指向
Object
,因为在 JS 中,万物皆为对象。而 Object 指向的终点,会是null
2. Vue 中一个重要的原型关系
Vue 中有许多 API,我们都无需声明便可以直接调用,比如
$set
、$watch
等,你思考过为什么吗?
1)首先给出结论
- 这些可供调用的 API,都 存放在 Vue 的原型对象 中
- 不管是 Vue 的
实例对象
(下文统称vm),还是组件对象
(下文统称vc),最终都会指向 Vue 的原型对象
- 综上两点所述,vm 和 vc 中,都可以 通过原型找到 Vue 原型对象身上的方法 进行调用
2)Vue 内部是如何做到的
vm
与其原型对象的关系如下:
vc
与其原型对象的关系如下:
注意!
如果 vc 的原型对象,直接指向了 Object,那么 vc 是 无法获取 Vue原型对象身上的方法和属性,也就是无法调用到 $set
这类API;因此 Vue 将 vc.__proto__
的指向进行了改变,指向了 Vue的原型对象,让 vc 也能获取到 Vue原型对象身上的方法和属性(如下图 红色箭头
)
正因上图中红色箭头的关系,让我们能在任意一个组件实例中(也就是 .vue
文件)中,调用到 Vue身上的各种API~
3. 总结
prototype | __proto__ |
---|---|
显示原型 | 隐式原型 |
只存在于构造函数(如:Vue 构造函数) | 只存在于实例对象(如:vm) |
[程序员] 通过 prototype 上 添加属性,如 Vue.prototype.xxx = xxx | [程序] JS 自动沿着 __proto__ 向上寻找属性和方法 |