1 概述
我们可能听说过这句话,“ JavaScript 不是面向对象的语言,它是面向原型的。”
先看一下例子:
({} instanceof Object)
([] instanceof Object)
function Foo() {}
((new Foo) instanceof Object)
JavaScript 确实包含对象,所以不能说它不面向对象。确切滴说,JavaScript 是面向对象、面向原型的语言。
2 为什么要有原型?
原型是嵌入在对象中的 “特殊对象”。在 JavaScript 中,我们可以通过属性 __proto__ 来访问它。
const witch = { name: "Hermione" }
witch.__proto__
原型的特别之处在于,它可以透明地充当某种“代理”或“备份”。如果我们尝试访问一个对象中不存在的属性,如果原型中有这个属性,那么 JavaScript 将返回原型的属性。
witch.__proto__.spells = { leviosa: "Wingardium leviosa" }
witch
witch.spells
这就是原型的作用,在对象之间共享代码。在 JavaScript 中,没有传统面向对象中类的概念,只有原型。
当我们使用构造函数实例化对象时,就能很容易看到这一点。如果我们有 Wizard 函数,那么每次用 new Wizard() 创建一个新对象,属性 Wizard.prototype 就会变成新创建实例的原型。
function Wizard(name) {
this.name = name || "Anonymous"
}
Wizard.prototype.spells = {
leviosa: "Wingardium leviosa",
expelliarmus: "Expelliarmus",
patronus: "Expecto patronum"
}
const draco = new Wizard("Draco")
// => Wizard { name: "Draco" }
const hermione = new Wizard("Hermione")
// => Wizard { name: "Hermione" }
draco.spells === hermione.spells
// => true (both wizards share spells)
draco.__proto__ === hermione.__proto__
// => true (that's why they share prototypes)
hermione.__proto__ === Wizard.prototype
// => true (their prototype is defined in Wizard.prototype)
原型的好处
- 节省内存,原型是共享的,不是每个对象都有一个副本
- 修改原型,可以动态地修改多个对象
如果对象中的属性与原型属性具有相同的名称,那么对象中的属性优先级高。
const newbie = new Wizard("Lorem")
newbie.spells = {} // bypass what's in the prototype
newbie.spells === hermione.spells
// => false
|