下面是一些示例,展示了基于对象定义和创建方式的原型(prototype)继承的不同行为。我区分对象的“原型(prototype)属性”,例如someObject.prototype
和“原型(prototype)引用”(我认为它应该指的是 someObject
继承的对象?)。
例子1
这似乎是保留父对象原型(prototype)属性的方法。这不是推荐的继承方式吗?
// create object whose prototype reference is Object; add stuff.
var Parent = Object.create(Object);
Parent.a = "1";
Parent.f = function() { return true; };
// add stuff to prototype property
Parent.prototype.b = 1;
Parent.prototype.g = function() { return false; };
// create an object whose prototype reference is Parent (??)
var Child = Object.create(Parent);
console.log(Parent.__proto__) // [Function: Object]
console.log(Parent.prototype) // { b: 1, g: [Function] }
console.log(Child.__proto__) // { a: '1', f: [Function] }
console.log(Child.prototype) // { b: 1, g: [Function] }
我原以为
Child.__proto__
会以与Parent.__proto__
命名相同的方式命名
。Parent
对象我们看到
Child
的原型(prototype)引用指向Parent
的属性,而不是Parent.prototype
的属性。这是违反直觉的,至少对我来说是这样,因为我本以为会看到Parent.prototype
的属性b
和g
。
例子2
混合结果。
// use a constructor instead.
var Parent = function () {
this.a = "1";
this.f = function() { return true; };
}
// again, add stuff to prototype property.
Parent.prototype.b = 1;
Parent.prototype.g = function() { return false; };
// create an object whose prototype reference is Parent (??)
var Child = new Parent();
// create differently
var Sibling = Object.create(Parent);
console.log(Parent.__proto__) // [Function: Empty]
console.log(Parent.prototype) // { b: 1, g: [Function] }
console.log(Child.__proto__) // { b: 1, g: [Function] }
console.log(Child.prototype) // undefined
console.log(Sibling.__proto__) // [Function]
console.log(Sibling.prototype) // { b: 1, g: [Function] }
这里,
Child
的原型(prototype)引用了Parents.prototype
的属性。这就是我上面所期望的?另一方面,
Sibling
的原型(prototype)引用现在是一个函数,它是Parent
的原型(prototype)引用。
示例 3
这似乎是保留父对象的原型(prototype)引用的方法,但是您丢失了它的原型(prototype)属性。
// create object constructor; add stuff.
var Parent = function () {
this.a = "1";
this.f = function() { return true; };
}
// add stuff to prototype property.
Parent.prototype.b = 1;
Parent.prototype.g = function() { return false; };
// create an object whose prototype reference is Parent (??)
var Child = function() {
this.c = "2";
};
// supposed Ad-hoc prototype inheritance
Child.prototype = Object.create(Parent.prototype)
console.log(Parent.__proto__) // [Function: Empty]
console.log(Parent.prototype) // { b: 1, g: [Function] }
console.log(Child.__proto__) // [Function: Empty]
console.log(Child.prototype) // {}
示例 1 中显示的方法是否是首选,因为您可以访问父级的原型(prototype)属性、它自己的属性以及 Object
的属性/方法?我在其他帖子中读到,其中一些继承方式应该是平等的……这是不正确的。另外,我读过其他帖子,例如here , Example 3 是可行的方法。或者我只是不确定 __proto__
代表什么......
感谢您对这些混合搭配情况之间的差异做出的任何澄清!
最佳答案
I distinguish between the "prototype member" of an object, e.g. someObject.prototype and the "prototype reference"
好的术语,区分它们是理解它们的第一步and the difference between them .
(which I think should refer to the object from which someObject inherits?).
没错。与 .prototype
成员不同,您可以通过 Object.getPrototypeOf(obj)
访问原型(prototype)引用或非标准的 .__proto__
属性。
Example 1
Isn't this the recommended way of inheriting?
这是进行继承的一种方式,也是最纯粹的原型(prototype)继承形式。请注意,Parent
和 Child
是普通对象,不涉及构造函数。
// create object whose prototype reference is Object; add stuff. var Parent = Object.create(Object);
这是第一个错误:您继承自 Object
function(它基于构造函数模式,见下文)。你应该做
var Parent = {};
// or
var Parent = Object.create(Object.prototype);
// add stuff to prototype member Parent.prototype.b = 1; Parent.prototype.g = function() { return false; };
但是,.prototype
成员在这种继承模型中没有任何意义。它只是一个普通属性,在本例中是从 Object
继承的。你实际上是在修改 Object.prototype
对象(大禁忌)!
// create an object whose prototype reference is Parent (??) var Child = Object.create(Parent);
是的,就是这样Object.create
[Example 1 / 1] I would have expected Child.proto to be something naming Parent in the same way Parent.proto names Object.
它命名 Object
只是因为它是一个命名函数。无法在运行时从对象引用中获知变量名 Parent
。
[Example 1 / 2] We see that Child's prototype reference points to the members of Parent rather than the members of Parent.prototype. This is counterintuitive, to me at least, as I would have expected to see Parent.prototype's members b and g instead.
是的,您直接继承自 Parent
对象。 .prototype
如上所述是微不足道的。 Child.prototype === Object.prototype
(继承了两次)。
Example 2 - use a constructor instead. Adding stuff to its prototype member.
// create an object whose prototype reference is Parent (??) var Child = new Parent();
[Example 2 / 1] Here, Child's prototype references Parents.prototype's members. This is what I expected above?
没有。 new
operator创建对提供的构造函数的 .prototype
成员值的原型(prototype)引用 - 在本例中为 Parent.prototype
。
// create differently var Sibling = Object.create(Parent);
同样,您在这里创建了一个对象,该对象具有对函数的原型(prototype)引用。不是你想要的 - 而是使用
var sibling = Object.create(Parent.prototype);
Parent.call(sibling); // optionall apply the constructor on it, like `new` does
[Example 2 / 2] On the other hand, Sibling's prototype reference is now a function, which is the prototype reference of Parent.
更准确地说,它是Parent
函数本身。这就是为什么您的 Sibling
确实继承了 .prototype
属性。
Example 3 - This seems to be the way to preserve the parent object's prototype reference, but you lose its prototype member:
// supposed Ad-hoc prototype inheritance Child.prototype = Object.create(Parent.prototype)
这是为构造函数方式设置继承(原型(prototype)引用)链所必需的。这是在 JavaScript 中实现“类”模式的标准方式。
console.log(Parent.__proto__) // [Function: Empty] console.log(Parent.prototype) // { b: 1, g: [Function] } console.log(Child.__proto__) // [Function: Empty] console.log(Child.prototype) // {}
正如您在此处看到的,Parent
和 Child
都是函数 - 确切地说是构造函数。您需要调用它们:
var childInstance = new Child();
console.log(childInstance) // {c: "2"}
console.log(childInstance.prototype) // undefined - it's not a constructor
console.log(childInstance.__proto__) // {} - the Child.prototype object
console.log(childInstance.__proto__.__proto__) // the Parent.prototype object
console.log(childInstance.__proto__.__proto__.__proto__) // the Object.prototype object
但是,您忘记了一步。 childInstance
确实从 Parent.prototype
继承了 b
和 g
,但没有 a
和 f
proeprties 在 Parent
构造函数中创建。对于 correct inheritance in the constructor model您还必须在每个实例上应用 Parent
构造函数,最好是在 Child
构造函数中:
function Child() {
Parent.call(this);
this.c = "2";
}
var childInstance = new Child();
console.log(childInstance) // {a: 1, f: [Function …], c: "2"}
关于Javascript __proto__ 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24004669/