【问题标题】:Can someone clarify the ambiguity of the words prototype and constructor? [closed]有人可以澄清原型和构造函数这两个词的歧义吗? [关闭]
【发布时间】:2019-07-15 17:55:24
【问题描述】:

作为一个面向对象的 JavaScript 新手,我注意到没有过多强调语言“原型”和“构造函数”的歧义所造成的混乱,这让我怀疑我是否走在正确的轨道上或误解了整个概念。

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

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

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

其次,构造器这个词经常被松散地使用,至少在初学者眼中是这样。例如,当人们说构造函数的原型时,他们是指person1 的函数Person(),其中person1 是Person() 的实例吗?或者他们的意思是person1.constructor?当说“构造函数的原型”时,是指 Object.constructor.prototype 还是构造函数 Person() 的原型?

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

【问题讨论】:

  • 好吧,“原型”和“构造函数”是相关的概念,但它们指的是完全不同的东西。 “构造函数”始终是一个函数,而“原型”可以是一个函数,但几乎总是只是一个常规对象。
  • 就像我说的,MDN 页面是错误的。 Tree() 不是原型,它是构造函数。我已经修复了页面。 “constructor”属性是对用于实例化对象的构造函数的引用。
  • @Kevvv 它是一个构造函数,是类实例的“构造函数”,因此将指向它的属性称为.constructor 是明智的。还能是什么?我没有看到任何歧义。
  • @Bergi 所以当我说树的构造函数是什么时,它是否应该总是表示 tree.constructor 和 Tree 因为它们指向同一个东西并且行为相同?
  • @Kevvv 是的,Tree 函数是tree 的构造函数——它是使用new Tree 构造的。它也可以通过tree.constructor 访问。鉴于它们是同一个东西,“树的构造函数”这个词没有歧义:-)当然,在边缘情况下,它们指的是不同的东西,然后 - 但只有那时 - 它是重要的是要准确区分“tree 对象的.constructor 属性”和“用于构造tree 对象的函数”。

标签: javascript oop constructor prototype


【解决方案1】:

用代码说明问题。

// 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)

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

上面的代码链如下所示:

Object.prototype <- Tree.prototype <- treeInstance

所以...

  • “构造函数”是初始化实例的函数。它始终是一个函数。构造函数中的this 是您的未来实例。
  • “原型”是 JS 在无法在实例上找到某些内容时询问的下一个“事物”。这个“东西”通常是一个对象,但它可以是任何东西。

【讨论】:

  • 感谢您的明确解释。当“原型”用在“原型是 JavaScript 对象相互继承特性的机制”这样的句子中时,它并不完全是指 Tree.prototype,对吗?它指的是OOP允许继承的机制,而不是包含hasOwnProperty()或isOwnPropertyOf()等方法的属性;
  • @Kevvv 了解 JavaScript 中的“OOP”与 Java、C++ 或 C# 中的 OOP 有很大不同。
  • 我说的是OOJS。
猜你喜欢
  • 2020-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-20
  • 2014-05-21
  • 1970-01-01
  • 2018-03-19
相关资源
最近更新 更多