前言
在 JavaScript 中,原型链 是实现继承的核心机制,也是理解框架设计(如 Vue)的重要基础。而 Vue 组件(VueComponent
)的原型设计,更是直接依赖于 JS 原型链的特性 ------ 通过原型链关联,让组件实例(vc
)能访问 Vue 原型上的属性和方法。
一、完整源码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<student></student>
</div>
</body>
<script>
/*
function Person(){
this.name = "张三"
}
此时Person有自己的原型,其原型的原型(Person.prototype.prototype)是Object的原型(Object.prototype)
访问原型方式(两者等价):
1 Person实例.__proto__
2 Person.prototype
Person.prototype.age = 18 //通过类给原型添加属性
let person = new Person()
person.__proto__.sex = '男'//通过对象给原型添加属性
console.log(new Person()) //Person对象有自己的属性name和原型属性age、sex
对象访问属性时:
1 找自身实例是否有该属性;
2 找实例的原型是否有该属性(如Person实例.__proto__);
3 就继续顺着原型链往上找(如Person实例.__proto__.__proto__,此时为Object的原型)
4 Object的原型的原型为null(返回 undefined)。
*/
const student = Vue.extend({
template:`
<div>
<h1>学生名称:{{name}}</h1>
<h1>学生年龄:{{age}}</h1>
</div>
`,
data() {
return {
name:'张三',
age:'18'
}
}
})
const vm = new Vue({
el:'#root',
data() {
return {
n:1
}
},
components:{
student
}
})
/*
重要的内置关系:new student().__proto__.__proto__ === Vue.prototype。即VueComponent原型的原型===Vue的原型
因此,vc可以访问Vue原型上的属性、方法
*/
console.log(new student().__proto__.__proto__ === Vue.prototype) // true
</script>
</html>
二、核心知识点解析
1. JavaScript 原型链:从 Person 构造函数说起
原型链的核心逻辑是:每个实例对象都有一个__proto__
(原型),其__proto__
又指向更高层的原型,直到指向Object原型对象.__proto__ = null
(原型链终点)。
1.1 代码中原型链的关键操作
-
构造函数与实例的关系 :
new Person()
创建的实例,其__proto__
===Person.prototype
(这是原型链的起点)。javascriptlet p = new Person(); console.log(p.__proto__ === Person.prototype); // true
-
两种操作原型的方式 :
- 通过构造函数操作:
Person.prototype.age = 18
(直接给Person
的原型添加age
属性); - 通过实例操作:
person.__proto__.sex = '男'
(实例的__proto__
就是Person.prototype
,本质和第一种方式一致)。
- 通过构造函数操作:
-
原型链查找规则 :当访问实例的属性时,会优先查找自身属性 → 若没有则找
__proto__
(构造函数原型)→ 再找__proto__.__proto__
(更高层原型)→ 直到null
(找不到返回undefined
)。
例如访问new Person().age
:实例自身没有age
→ 找Person.prototype.age
(存在,返回 18)。
2. Vue 组件原型关系:为什么 VC 能访问 Vue 原型的方法?
Vue 中的组件(VueComponent
,简称VC
)是通过Vue.extend
创建的构造函数,其原型设计直接依赖 JS 原型链,核心结论是:VC实例.__proto__.__proto__ === Vue.prototype
。
2.1 代码中验证
javascript
console.log(new student().__proto__.__proto__ === Vue.prototype); // true
2.2 这个设计的意义是什么?
Vue 的原型(Vue.prototype
)上挂载了很多全局方法(如$emit
、$on
、$nextTick
等)。通过将VC
的原型链指向Vue.prototype
,VC
实例就能直接访问这些方法,无需重复定义,实现了方法复用。
例如,我们可以在Vue.prototype
上添加一个全局方法,然后在组件中直接调用:
javascript
// 给Vue原型添加全局方法
Vue.prototype.sayHi = function() {
alert('Hi,我是Vue原型上的方法!');
};
// 在student组件中调用
const student = Vue.extend({
template: `
<div>
<!-- 其他内容 -->
<button @click="sayHi">调用全局方法</button>
</div>
`,
// ...其他配置
});
点击按钮时,VC
实例会通过原型链找到Vue.prototype.sayHi
,成功执行方法。