在 JavaScript 中,prototype 和 __proto__ 都与原型链相关,但它们的角色和用途有本质区别:
1. prototype 和 __proto__ 的区别
 
| 特性 | prototype | __proto__ | 
|---|---|---|
| 归属对象 | 仅函数对象拥有(如构造函数) | 所有对象默认拥有(包括函数对象) | 
| 作用 | 定义构造函数创建实例时的原型模板 | 指向实例对象的实际原型对象 | 
| 关系 | 构造函数的 prototype 是实例的 __proto__ | 实例的 __proto__ 指向其构造函数的 prototype | 
| 示例 | function Foo() {}Foo.prototype | const obj = {}obj.__proto__ | 
核心区别
-  
构造函数视角:
函数的prototype是一个显式定义的模板对象,用于给所有通过new创建的实例提供共享属性和方法。 -  
实例视角:
对象的__proto__是一个隐式引用,指向它的构造函数的prototype,形成原型链。 
代码示例
function Person(name) {this.name = name;
}// 构造函数的 prototype 定义共享方法
Person.prototype.sayHello = function() {console.log(`Hello, I'm ${this.name}`);
};const alice = new Person("Alice");// 实例的 __proto__ 指向构造函数的 prototype
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
 
2. 手动修改对象的原型
JavaScript 允许通过以下方式动态修改对象的原型:
方法 1:Object.setPrototypeOf(obj, proto)
 
- 作用:直接设置对象的 
[[Prototype]](即__proto__)。 - 示例:
const parent = { value: 42 }; const child = {};// 修改 child 的原型为 parent Object.setPrototypeOf(child, parent);console.log(child.value); // 42(通过原型链访问) 
方法 2:obj.__proto__ = proto
 
- 作用:通过 
__proto__属性直接赋值(非标准,但广泛支持)。 - 示例:
const parent = { value: 42 }; const child = {};child.__proto__ = parent; console.log(child.value); // 42 
方法 3:创建时指定原型(Object.create())
 
- 作用:在对象创建时直接指定原型。
 - 示例:
const parent = { value: 42 }; const child = Object.create(parent); // child 的原型是 parentconsole.log(child.value); // 42 
注意事项
-  
性能问题:
动态修改原型(如Object.setPrototypeOf)可能影响 JavaScript 引擎的优化,尽量避免在性能敏感场景使用。 -  
更安全的替代:
优先使用Object.getPrototypeOf(obj)获取原型,避免直接操作__proto__。 -  
构造函数场景:
若需批量修改实例的原型,应直接修改构造函数的prototype:function Animal() {} Animal.prototype.eat = function() {};function Dog() {} // 让 Dog 的实例继承 Animal 的原型 Dog.prototype = Object.create(Animal.prototype); 
总结
prototype是构造函数的显式原型模板,__proto__是实例的隐式原型引用。- 修改原型时,优先使用 
Object.create()或Object.setPrototypeOf(),避免直接操作__proto__。 
