proto 原始
英 美[ˈproʊtə]
prototype 和 __proto__ 的出现,正是 JavaScript 原型链的核心设计。
让我详细解释这个看似”混乱”但实际非常精妙的设计:
1. 根本原因:JavaScript 语言设计
JavaScript 中只有 函数对象才拥有 prototype 属性,而所有对象都拥有 __proto__ 属性。这是JavaScript语言的规定,不是 Vue 特有的。
2. 三者的本质区别
| 对象类型 | 是否有 prototype | 是否有 __proto__ | 原因 | 
|---|---|---|---|
| Vue 构造函数 | ✅ 有 | ✅ 有 | 函数对象天生有 prototype,用于定义实例共享方法 | 
| Vue 实例对象 | ❌ 无 | ✅ 有 | 实例是普通对象,只需通过 __proto__继承方法,无需自己定义原型 | 
| Vue 原型对象 | ❌ 无 | ✅ 有 | Vue.prototype本身也是对象,通过__proto__继承Object.prototype | 
3. 内存结构可视化
4. 具体代码验证
// 1. Vue 构造函数(函数对象)
console.log(typeof Vue); // "function"
console.log(Vue.hasOwnProperty('prototype')); // true(函数特有)
console.log(Vue.__proto__ === Function.prototype); // true(继承Function原型)
// 2. Vue 原型对象(普通对象)
console.log(typeof Vue.prototype); // "object"
console.log(Vue.prototype.hasOwnProperty('prototype')); // false(非函数,无prototype)
console.log(Vue.prototype.__proto__ === Object.prototype); // true(继承Object原型)
// 3. Vue 实例对象(普通对象)
const vm = new Vue();
console.log(typeof vm); // "object"
console.log(vm.hasOwnProperty('prototype')); // false(实例无prototype)
console.log(vm.__proto__ === Vue.prototype); // true(继承Vue原型)5. 设计哲学解析
为什么函数有 prototype?
function Vue() {} // 构造函数
// prototype 的用途:定义实例共享的蓝图
Vue.prototype.$mount = function() { /* 所有实例共享 */ };
Vue.prototype.$watch = function() { /* 所有实例共享 */ };
const vm = new Vue();
vm.$mount(); // 通过原型链找到共享方法设计理由:函数作为”构造函数”时,需要 prototype 来存储所有实例共享的方法模板。
为什么实例没有 prototype?
const vm = new Vue();
// 实例是"产品",不需要生产其他对象
console.log(vm.prototype); // undefined
// 实例只需继承方法,无需定义新原型
console.log(vm.__proto__ === Vue.prototype); // true设计理由:实例是终端的”产品对象”,不再用于创建其他对象,故无需 prototype。
6. 完整的原型链验证
const vm = new Vue();
// 完整的原型链
console.log(vm.__proto__ === Vue.prototype); // true
console.log(Vue.prototype.__proto__ === Object.prototype); // true  
console.log(Object.prototype.__proto__ === null); // true
// 构造函数本身的继承链
console.log(Vue.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true7. 实际内存布局
内存地址 0x100: [Vue 构造函数]
  - prototype: 0x200(指向原型对象)
  - __proto__: 0x300(指向Function.prototype)
内存地址 0x200: [Vue.prototype 原型对象]  
  - $mount: function() {}
  - $watch: function() {}
  - __proto__: 0x400(指向Object.prototype)
内存地址 0x500: [vm 实例对象]
  - _data: {...}(实例自有数据)
  - __proto__: 0x200(指向Vue.prototype)8. 与 ES6 class 的对比
ES6 class 是语法糖,底层仍是原型继承:
class Vue {
  constructor() { this._data = {}; }
  $mount() { /* 方法 */ }
}
// 等价于
function Vue() {
  this._data = {};
}
Vue.prototype.$mount = function() {};
const vm = new Vue();
console.log(vm.__proto__ === Vue.prototype); // true(原理相同)9. 总结回答
- Vue 构造函数有 - prototype- 因为它是函数对象,需要定义实例的共享蓝图
 
- Vue 实例只有 - __proto__- 因为实例是普通对象,只需继承方法,无需生产新对象
 
- Vue 原型对象有 - __proto__- 因为 Vue.prototype本身也是对象,需要继承Object的原型方法
 
- 因为 
核心记忆点:
- 函数:prototype(定义蓝图) +__proto__(继承功能)
- 对象:只有 __proto__(纯消费者)
- 设计目的:实现高效的方法共享和内存优化
这种设计确保了 JavaScript 的对象系统既灵活又高效,是语言的核心特性之一。
 我的书签
 我的书签
                                 添加书签
 添加书签 移除书签
 移除书签