浅谈JS里的prototype与__proto__

81 阅读2分钟

小结:

  1. 每个类都有且仅有一个原型对象

  2. 每个类可以有多个实例对象

  3. 实例对象(a)的__proto__属性指向该类(A)的原型对象,即:a.__proto__ === A.prototype

  4. 自定义对象A的原型对象(A.prototype)是Object类的实例对象,结合第3条得出结论:A.prototype的__proto__属性指向该类(Object)的原型对象,即A.prototype.__proto__ === Object.prototype

  5. 结合第3、4条,可得:a.__proto__.__proto__ === Object.prototype,这就是原型链

  6. Object类是所有类的源头,所以 Object.prototype.__proto__ === null image.png

  7. 而A、Object都是构造函数(类),即:A、Object都是函数对象,即A、Object都是Function类的实例对象,结合第3条得出结论:A.__proto__ === Function.prototypeObject.__proto__ === Function.prototype

  8. 而Function也是构造函数(类),即Function也是函数对象,即Function是Function类的实例对象,结合第3条得出结论:Function.__proto__ === Function.prototype image.png

  9. Function跟A一样,它的原型对象是Object类的实例对象,即:Function.prototype.__proto__ === Object.prototype

  10. 类中定义的属性都在实例对象上,定义的方法都在原型对象上。

image.png

详述:

在 JavaScript 中,prototype 和 proto 都与类的原型机制有关,但它们有不同的用途和含义。以下是对它们的详细解释:

prototype

  • prototype 是函数对象的一个属性。每一个函数在创建时都会自动拥有一个 prototype 属性,这个属性是一个对象,包含了特定类型的对象实例共享的属性和方法。
  • 当你使用构造函数创建一个对象时,这个对象的 proto 属性会指向构造函数的 prototype 属性。
  • prototype 属性主要用于实现基于原型的继承。

示例

// 定义一个构造函数
function Person(name) {
  this.name = name;
}

// 向构造函数的 prototype 属性添加方法
Person.prototype.greet = function() {
  console.log('Hello, ' + this.name);
};

// 创建一个实例
const alice = new Person('Alice');

// 使用实例调用 prototype 方法
alice.greet(); // 输出:Hello, Alice

在这个示例中,Person.prototype 包含了所有实例共享的方法。当你创建一个新的 Person 实例时,这个实例会继承 Person.prototype 上的所有方法。

proto

  • proto 是每一个 JavaScript 对象的内部属性。它指向该对象的构造函数的 prototype 属性,即该对象的原型。
  • proto 是用来访问对象的原型的,是 JavaScript 中实现原型链的关键。
  • 虽然可以直接访问和修改 proto 属性,但不推荐这样做,因为这会影响性能和代码的可维护性。更推荐使用 Object.getPrototypeOf 和 Object.setPrototypeOf 方法。

示例

// 创建一个对象
const obj = {};

// obj 的原型是 Object.prototype
console.log(obj.__proto__ === Object.prototype); // 输出:true

// 创建一个构造函数
function Animal() {}

// 创建一个实例
const dog = new Animal();

// dog 的原型是 Animal.prototype
console.log(dog.__proto__ === Animal.prototype); // 输出:true