【问题标题】:Javascript: What's the logic behind the default value of prototype property of a function/class? [duplicate]Javascript:函数/类的原型属性的默认值背后的逻辑是什么? [复制]
【发布时间】:2020-03-08 12:30:28
【问题描述】:

我们知道 JavaScript 有原型继承而不是经典继承,这意味着每个对象 具有 [[Prototype]] 属性,可用于通过原型链进行继承。

然而,我无法理解的这个原型继承模型的一部分是函数(或类)对象最初获得的默认原型属性背后的逻辑。即

  //For classes
  class Dog {}
  Dog.prototype // {constructor: Dog}

  //For functions
  function Cat() {}
  Cat.prototype // {constructor: Cat};

让这个属性包含指向函数本身的构造函数属性的可能用途是什么?我理解一种用法,即创建的任何对象都将获得构造函数属性,并且如果定义以某种方式丢失(像这样),则可用于创建更多对象:

function Dog(name) {
  this.name = name;
  alert(name);
}

let dog = new Dog("White Dog");

let dog2 = new dog.constructor("Black Dog");

但这并不能证明这样的设置是合理的,老实说这是相当复杂的(因为函数/类是唯一对自身具有这种循环引用的对象)。这个决定背后还有其他原因吗?

【问题讨论】:

  • 可以使用dog.constructor获取用于创建对象的构造函数/类
  • prototype 属性是一个对象,可用于您使用构造函数创建的任何实例:该原型对象将是原型链中实例的父对象。
  • 在引入class 语法之前,除了分配给构造函数的prototype 属性之外,没有其他方法可以定义“类”的所有实例(例如方法)共有的成员。所以这也是历史的事情……
  • 我不认为这符合您的预期:new Dog.constructor("return 1+1")() == 2。回顾一下:函数是对象,它们有一个原型属性,您可以填充在使用new 调用函数并返回对象时继承的成员。 function.prototype 主要是暴露出来的,所以你可以修改它,迭代它等等。它是继承链的样子。
  • @adiga 是的,我确实在帖子中提到了这种用法。想知道是否还有其他有用的东西

标签: javascript function inheritance prototype


【解决方案1】:

(已更新以回答实际问题,请参阅下面的旧答案)

这个决定背后还有其他原因吗?

我只能猜测,但它可能来自影响 javascript 的语言的设计。在pure prototype-based programming 中,根本没有构造函数。只有原型对象本身来定义一个“类”,并且它将有一个init 方法可以在从它派生的实例上调用。伪语言示例:

dog = object create()
dog init = (name) {
  this name = name
}
mydog = dog create()
mydog init("whitey")

注意mydog 是如何从dog 继承的,而dog 又是从object 继承的。 dog 对象有一个 init 方法,这是自然链接。辅助方法new 可能将createinit 捆绑在一起,称为mydog = dog new("blackey")

现在在 JavaScript 中,一切都变成了对象,甚至函数/方法本身也是如此。为了看起来更像 Java(当时很流行),new 被做成了一个操作符而不是一个继承的方法。出于某种原因,决定不将其应用于原型对象,而是应用于构造函数——为此,它被赋予了.prototype 属性。也许这样可以用简单的function 声明类?或者通过使用自定义对象覆盖.prototype 来启用继承?我不知道。

无论如何,.constructor 是两个循环属性中更自然的一个。没有.prototype,我们可以轻松生活:

 // assuming builtins:
 const object = Object.create(null)
 object.create = function() { return Object.create(this) }
 object.new = function() { const o = this.create(); o.constructor(); return o }

// we would use them as (assuming the object literal to inherit from `object`)
var Dog = {
  constructor(name) { this.name = name },
  woof() { alert(this.name + "makes: Woof!") }
}
var myDog = Dog.new("Whitey")
myDog.woof()

强大的力量来自被用作使用new 运算符创建的所有实例的 [[prototype]] 的对象:

const mydog = new Dog("White Dog");
console.assert(Object.getPrototypeOf(mydog) === Dog.prototype)

这是类的中心对象,所有共享方法都在其中。其中的.constructor property 只是一个有用的(if rarely used)默认值。但是你会写

Dog.prototype.woof = function() {
    alert(this.name + "makes: Woof!");
};

并且该方法可以通过继承获得

dog.woof();

使用class 语法定义方法会导致相同的Dog.prototype 对象。

【讨论】:

  • 我明白为什么要使用原型属性了。但是我想知道为什么这个原型有一个这样的初始/默认值,构造函数指向原始函数本身。
  • @VSX 我可能误解了你的问题,但你问的是“函数/类的默认 .prototype 属性背后的逻辑是什么?”?
  • @VSX 不,.constructor 属性不是指向原型对象本身,而是指向构造函数。
  • 我的错。更新了标题。是的,我的意思是只有指向原始函数的构造函数。
猜你喜欢
  • 2021-03-30
  • 2017-10-17
  • 2010-12-06
  • 1970-01-01
  • 2022-08-14
  • 2014-07-15
  • 1970-01-01
  • 2011-01-21
  • 2011-11-02
相关资源
最近更新 更多