下面是一些示例,展示了基于如何定义和创建对象的原型继承的不同行为。我区分"原型属性"一个物体,例如someObject.prototype
和"原型参考" (我认为应该引用someObject
继承的对象?)。
这似乎是保留父对象原型属性的方法。这不是推荐的继承方式吗?
// 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
名称Parent.__proto__
的方式命名Object
。
我们看到Child
的原型引用指向Parent
的属性,而不是Parent.prototype
的属性。至少对我来说,这是违反直觉的,正如我原本预期的那样,我会看到Parent.prototype
的属性b
和g
。
混合结果。
// 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
的原型参考Parents.prototype
的属性。这是我上面的预期?
另一方面,Sibling
的原型参考现在是一个函数,它是Parent
的原型参考。
这似乎是保留父对象原型引用的方法,但是你丢失了它的原型属性。
// 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 中显示的方法是否首选,因为您可以访问父级的原型属性,自己的属性以及Object
的属性/方法?我在其他帖子中读过,其中一些继承方式应该是平等的......这是不正确的。此外,我还阅读了其他帖子,例如here,示例3 是要走的路。或许我只是不确定__proto__
代表什么......
感谢您对这些混合和匹配情况之间的差异所做的任何澄清!
答案 0 :(得分:2)
我区分"原型成员"一个物体,例如someObject.prototype和"原型参考"
良好的术语,区分它们是理解它们的第一步and the difference between them。
(我认为应该引用someObject继承的对象?)。
完全。与.prototype
成员相比,您可以通过Object.getPrototypeOf(obj)
或非标准.__proto__
属性访问protypte引用。
示例1
这不是推荐的继承方式吗?
它是一种方式进行继承,以及最纯粹的原型继承形式。请注意,Parent
和Child
是普通对象,不涉及构造函数。
// create object whose prototype reference is Object; add stuff. var Parent = Object.create(Object);
这是第一个错误:您继承了Object
函数(基于构造函数模式,见下文)。你应该做的
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
所做的。
[例1/1]我原本期望Child。 proto 以同样的方式命名Parent. proto 命名Object。
它仅命名Object
,因为它是一个命名函数。在运行时,无法从对象引用中知道变量名Parent
。
[例1/2]我们看到Child的原型引用指向Parent的成员而不是Parent.prototype的成员。至少对我来说这是违反直觉的,因为我原本希望看到Parent.prototype的成员b和g。
是的,您直接从Parent
对象继承。 .prototype
如上所述是微不足道的。 Child.prototype === Object.prototype
(它继承了两次)。
示例2 - 改为使用构造函数。将东西添加到其原型成员。
// create an object whose prototype reference is Parent (??) var Child = new Parent();
[例2/1]这里,Child的原型引用了Parents.prototype的成员。这是我上面所期待的?
没有。在这种情况下,new
operator创建了对所提供的构造函数的.prototype
成员的值的原型引用 - Parent.prototype
。
// create differently var Sibling = Object.create(Parent);
同样,在这里,您要创建一个具有函数原型引用的对象。不是你想要的 - 而是使用
var sibling = Object.create(Parent.prototype);
Parent.call(sibling); // optionall apply the constructor on it, like `new` does
[例2/2]另一方面,兄弟姐妹的原型参考现在是一个功能, 这是Parent的原型参考。
更确切地说,它是Parent
函数本身。这就是您Sibling
继承.prototype
财产的原因。
示例3 - 这似乎是保留父对象原型引用的方法,但是您丢失了原型成员:
// supposed Ad-hoc prototype inheritance Child.prototype = Object.create(Parent.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
确实从b
继承了g
和Parent.prototype
,但没有在a
中创建f
和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"}
答案 1 :(得分:0)
要了解Object.create
的作用,首先需要了解为什么需要这样做。
JavaScript中原型设计的经典示例使原型成为继承对象的实例:
function Parent(field) {
this.field = field;
}
Parent.prototype.getField = function () { return this.field; }
function Child(field, field2) {
Parent.call(this, field);
this.field2 = field2;
}
Child.prototype = new Parent(null); // oops
Child.prototype.getField2 = function () { return this.field2; }
那" oops"当我们希望它只继承方法Child.prototype
时,field
行会getField
。你可以猜测这不是卫生的(语言方面的),并且可能会因为不那么重要的例子而变得混乱。
更简洁的方法是实例化未初始化的Parent
:
function inherit(parent) {
function temp() {
}
temp.prototype = parent.prototype;
return new temp();
}
Child.prototype = inherit(Parent);
该技术是使用相同的原型制作临时构造函数,这样在创建对象时,不会进行构造函数初始化。实际上,只建立了原型链。