Javascript __proto__ 输出

标签 javascript inheritance prototype

下面是一些示例,展示了基于对象定义和创建方式的原型(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] }
  1. 我原以为 Child.__proto__ 会以与 Parent.__proto__ 命名 相同的方式命名 Parent对象

  2. 我们看到 Child 的原型(prototype)引用指向 Parent 的属性,而不是 Parent.prototype 的属性。这是违反直觉的,至少对我来说是这样,因为我本以为会看到 Parent.prototype 的属性 bg

例子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] }
  1. 这里,Child 的原型(prototype)引用了 Parents.prototype 的属性。这就是我上面所期望的?

  2. 另一方面,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)继承形式。请注意,ParentChild 是普通对象,不涉及构造函数。

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

正如您在此处看到的,ParentChild 都是函数 - 确切地说是构造函数。您需要调用它们:

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 继承了 bg,但没有 af 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/

相关文章:

C++ - 是否需要类原型(prototype)?

javascript - js array.IndexOf 不能处理对象?

javascript - 如何让 Google 表格脚本在特定单元格的值发生变化时发送电子邮件?

c# - 在抽象基的构造函数中创建新的派生类型

C++继承/未声明的标识符问题

javascript - 创建 JS 对象的最优化方式

javascript - 在javascript中的某个位置找到单词

javascript - 我如何将 Javascript 对象写入文档。无法在 'write' 上执行 'Document'

inheritance - swift 从其基类返回子类

javascript - 对于 JavaScript 原型(prototype)继承,为什么不能在子构造函数中创建并保存父对象?