原型继承与原型链

2023-10-29
3分钟阅读时长

原型(prototype)

JavaScript 中的原型(prototype)实际上是一个对象,用于存储与其他对象共享的属性和方法。每个 JavaScript 对象都具有一个原型,它充当该对象的模板,并且可以从中继承属性和方法。

原型解决了 JavaScript 中的对象共享问题。在传统面向对象编程中,创建新对象需要定义类或构造函数,并使用该类或构造函数创建新实例。但在 JavaScript 中,我们可以通过原型来共享属性和方法,而无需为每个实例创建副本。这样可以节省内存,并使代码更加高效。

原型链

原型链是一种机制,用于查找对象属性和方法的过程。每个对象都有一个指向其原型的链接,我们称之为原型链。如果一个对象无法在自身属性中找到所需的属性或方法,它会沿着原型链向上搜索,直到找到匹配的属性或方法或者到达原型链的末端。

在 JavaScript 中,每个函数都有一个 prototype 属性,它是一个指向函数的原型对象的指针。当使用关键字 new 创建一个对象时,该对象的[[Prototype]](内部属性)会被设置为构造函数的 prototype 属性的值。

proto是每个 JavaScript 对象都具有的属性,它指向对象的原型。它实际上是对象的内部属性,用于连接对象与其原型之间的关系。尽管proto在早期 JavaScript 版本中被广泛使用,但它已经过时,并且不推荐在生产代码中使用。相反,应该使用 Object.getPrototypeOf()和 Object.setPrototypeOf()方法来访问和设置对象的原型。

区别

  • prototype 是函数特有的属性,用于定义构造函数的原型对象。
  • [[Prototype]]是每个对象都有的内部属性,用于指向对象的原型。
  • proto是旧的、不推荐使用的属性,用于访问和设置对象的原型,但可以通过 Object.getPrototypeOf()和 Object.setPrototypeOf()方法进行替代。

相关代码

// 构造函数
function Person(name) {
    this.name = name
}

// 构造函数原型对象上的方法,所有实例共享,且互相影响
Person.prototype.say = function() {
    console.log(`Hello, I'm ${this.name}`)
}

// 原型对象上的constructor指向构造函数
Person.prototype.constructor === Person // => true

// 创建实例
const p1 = new Person('Tom')

// 实例可以访问到原型对象(以及原型链)上的方法
p1.say() // => Hello, I'm Tom

// 对象的原型[[Prototype]]指向构造函数的原型对象prototype(推荐)
Object.getPrototypeOf(p1) === Person.prototype // => true

// 对象的原型__proto__指向构造函数的原型对象prototype(不推荐)
p1.__proto__ === Person.prototype // => true

// 对象就会有原型,原型又是对象,层层往上形成原型链,最终指向null,
p1.__proto__.__proto__.__proto__ === null // => true

总结

原型是 JavaScript 中实现对象共享属性和方法的机制,原型链用于属性和方法的查找,prototype 用于定义构造函数的原型对象,[[Prototype]]是对象内部指向原型的属性,而proto是用于访问和设置对象原型的不推荐使用的属性。