有人可以澄清原型和构造函数这两个词的歧义吗?

Can someone clarify the ambiguity of the words prototype and constructor?

作为一个面向对象的 JavaScript 新手,我注意到没有太多强调语言 "prototype" 和 "constructor" 的歧义造成的混淆,这让我想知道我是在正确的轨道上还是误解了整个概念。

例如here指的是下面的函数Tree:

function Tree(name) {
  this.name = name;
}

当还有一个 属性 称为原型时作为原型,如 Object.prototype。前者是函数的类型,而后者是对象的 属性。这有时会产生误导,因为当有人说一个对象的实例继承了其原型的特征时,他们实际上是说实例从称为原型的 object/function 类型继承了称为原型的 属性 (更不用说有原型 属性 之外的其他属性,如 Object.is() 或 Object.keys() 不被继承!)。

其次,constructor 这个词经常被随意使用,至少在初学者看来是这样。例如,当有人说构造函数的原型时,它们是指 person1 的函数 Person(),其中 person1 是 Person() 的实例吗?或者他们的意思是 person1.constructor?当一个人说 "constructor's prototype" 时,他们的意思是 Object.constructor.prototype 还是构造函数 Person() 的原型?

进一步加剧混淆的是,有时 person1.constructor 实际上等同于构造函数 Person(),而实际上它们是两个不同的东西。 person1.constructor 的构造函数是 person1 对象的 属性 而函数 Person() 是一种称为构造函数的函数。如果他们将称为构造函数的函数类型重命名为蓝图,那么人们很容易理解我所说的混淆是什么意思。

用代码说明问题。

// Tree is the "constructor".
function Tree(name) {
  this.name = name;
}

// Tree.prototype is Tree's "prototype"
// getName method is defined on Tree's prototype
Tree.prototype.getName = function(){
  return this.name
}

// When you instantiate a new Tree
const treeInstance = new Tree()

// The instance's constructor property references the constructor that
// created it. In this case, Tree.
console.log(treeInstance.constructor === Tree)

// The instance's prototype is Tree.prototype
console.log(Object.getPrototypeOf(treeInstance) === Tree.prototype)

// Here's the fun part. The instance has property "name"
console.log(treeInstance.hasOwnProperty('name') === true)

// But getName is NOT on the instance
console.log(treeInstance.hasOwnProperty('getName') === false)

// That's because getName lives on one of the prototypes.
// In this case, Tree.prototype
console.log(treeInstance.getName === Tree.prototype.getName)
console.log(treeInstance.getName === Object.getPrototypeOf(treeInstance).getName)

原型继承通过形成称为 "prototypes" 的对象链来工作。如果 JS 在对象上找不到某些东西,它会在对象的原型(通常是另一个对象)上寻找它。它递归地执行此操作直到没有更多,最后一个是 Object.prototype.

上面代码的链看起来像这样:

Object.prototype <- Tree.prototype <- treeInstance

所以...

  • A "constructor" 是初始化实例的函数。它始终是一个函数。 this 构造函数内部是您的实例。
  • A "prototype" 是下一个 "thing" JS 在无法在实例上找到内容时开始询问。这个 "thing" 通常是一个对象,但它可以是任何东西。