“原型”的反义词是什么?

8

请考虑以下内容:

var o = {foo: 'bar'};
var p = Object.create(o);

如果op的原型(prototype),那么相对于op是什么?

2
@yuan,我最初也想用那个措辞,但是原型不是“构造函数”。也就是说,p instanceof o会抛出TypeError。 - user2864740
1
确实。p instanceof o 是一个 TypeError - Amadan
@Amadan,但这没有任何意义。那几乎就是instanceof的意思,不是吗? - user3025492
它是针对所有对象还是只针对构造函数构建的对象? - user3025492
你只是在寻找一个名称吗?我会称之为“专业化”。 - woolstar
我删除了一条评论,因为它并不完全准确。对象没有构造函数属性,这是我的一个常见误解。它们的原型有。然后构造函数引用具有对它们的引用的原型。天哪,这很令人困惑,但这就是你不能通过引用constructor.prototype.constructor.prototype来爬升构造函数/原型树的原因,这是我在最近的另一个答案中犯的错误假设。 - Erik Reppen
3个回答

5

我不知道是否有关于继承自另一个对象原型的对象的正式术语达成普遍共识,但我认为“派生对象”这个术语是可以接受的。

原型继承的重点在于一个对象是从另一个对象继承而来的,或者说派生自另一个对象。在一些传统的面向对象编程语言中,例如C++,你会听到“派生类”这个术语,因为类是从其他类继承而来的。由于继承是在原型语言中两个对象之间进行的,因此我认为“派生对象”这个术语是合理的。


1
我不会使用“派生对象”这个术语,原因在我的回答中有详细阐述。 - Erik Reppen
@ErikReppen 我确实点赞了你的回答,但我在这里的回答是独立于JS的(没有考虑构造函数)。当一个对象是从原型“创建”出来时,它是一种派生:你从一个原型圆形中_派生_出一个圆形。这在JS中是正确的,因为每个函数都有一个原型属性,用于创建使用该函数创建的对象的原型,您可以动态地更改“类型”的性质。而且我确实相信,在JavaScript中,newObject.create更好。不过,Object.create确实表示“像这个现有对象一样创建一个新对象”。 - Ray Toal
我对JS之外的原型不是非常熟悉,但我认为在更广泛的上下文中,属性是通过克隆而不是通过调用对象引用现有对象来附加的,这是一个公正的观点。 - Erik Reppen

4
注意:实际上,每个对象的原型实际上都有一个对构造函数的引用。因此,这里存在一些问题,尽管关于不是完全直接的关系的观点是正确的。原型对象仍然可以被替换,但实际上原型与对象相连,可以直接使用__proto__Object.getPrototypeOf(instance)proto不是标准,如果可用,则最好使用Object.getPrototypeOf)访问原型。
我认为更好的思考方式是将对象的构造函数视为其原型。将Object.create视为以下函数的函数形式:
function objCreate(prototypeObject){
    var constructor = function(){};
    constructor.prototype = prototypeObject;

    return new constructor;
}

所以在以下情况下:

var o = {foo: 'bar'};
var p = objCreate(o);

o被分配给p的构造函数的原型属性。

现在看看这个:

alert(p.foo);//'bar'

p.constructor.prototype = { foo: 'foobiedoobie', bar: 'ubarfu' }
alert(p.foo);//'foobiedoobie' // and we could access bar if we wanted to

使用"派生"或其他断言两种混合物之间存在直接关系的术语会使实际发生的事情变得模糊,因为您可以随时交换p的构造函数的原型属性,从而在回溯地更改所有p的构造函数实例可用的所有属性。p不是从o派生的。o是备份对象,如果您调用p没有的属性,则会检查其属性并进行检查。然后,如果该备份对象没有它,JS调用对象将检查其构造函数的原型,以此类推。
这就是为什么我个人不喜欢Object.create或即将推出的新类语法的原因。它们都是相同的,但我们毫无必要地掩盖了实际发生的情况,以获得一些非常小的语法糖胜利,这使得我们自己可以轻松地产生混浊的语法水域。
那么p与o有什么关系? p是一个构造函数的实例,在这个时候恰好具有o作为其原型。
没有直接关系。试图断言一个将只会让人们感到困惑,并且他们会错过它实际上是多么强大。在大多数语言中,您不能交换类并使所有新继承的属性突然可调用。在JS中,您可以。这是因为它更像是一系列备份对象,用于检查未直接设置在实例上的属性,而不是继承方案。

当你放弃传统的继承方法时,Object.create实际上会使事情变得更清晰。如果你的对象需要一个构造函数,只需添加一个“create”方法,该方法执行Object.create(this)并进行初始化即可。不需要将原型附加到构造函数上的混乱。 - rich remer
或者你可以创建一个方法来执行 Object.create 的操作 : )。虽然我并不是真的讨厌它,但我更希望这种努力能够用于创造一些更可怕的东西,以防止保护主义的编码者们接近,比如运算符重载之类的。 - Erik Reppen

0

在 o 的原型链下面会有 p,而在 p 的原型链上面会有 o。当某个成员无法直接在实例中找到时,原型链就会被使用。JavaScript 只会沿着原型链向上查找,直到找到该成员或返回 undefined:https://dev59.com/J2Qo5IYBdhLWcg3wbe5K#16063711

var o = {o:22}
var p = Object.create(o);
p.p = 33;
var q = Object.create(p);
console.log(q);
console.log(q.__proto__);
console.log(q.__proto__.__proto__);

我在询问术语命名。 - user3025492
@user3025492 不确定使用“派生”的术语是否好。它会让你想到基于类的术语。但我猜你可以随便称呼它,因为大多数JS程序员都对它的存在毫不知情:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain - HMR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接