简体   繁体   English

Javascript __proto__输出

[英]Javascript __proto__ output

Below are some examples showcasing the different behaviors of prototypal inheritance based on how the objects are defined and created. 下面是一些示例,展示了基于如何定义和创建对象的原型继承的不同行为。 I distinguish between the "prototype property" of an object, eg someObject.prototype and the "prototype reference" (which I think should refer to the object from which someObject inherits?). 我区分对象的“原型属性”,例如someObject.prototype和“原型引用”(我认为应该引用someObject继承的对象?)。

Example 1 例1

This seems to be the way to preserve the parent object's prototype property. 这似乎是保留父对象的prototype属性的方法。 Isn't this the recommended way of inheriting? 这不是推荐的继承方式吗?

// 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. I would have expected Child.__proto__ to be something naming Parent in the same way Parent.__proto__ names Object . 我原以为Child.__proto__是以Parent.__proto__命名Object方式命名Parent东西。

  2. We see that Child 's prototype reference points to the properties of Parent rather than the properties of Parent.prototype . 我们看到Child的原型引用指向Parent的属性而不是Parent.prototype的属性。 This is counterintuitive, to me at least, as I would have expected to see Parent.prototype 's properties b and g instead. 至少对我来说这是违反直觉的,因为我Parent.prototype期望看到Parent.prototype的属性为bg

Example 2 例2

Mixed results. 结果喜忧参半

// 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. Here, Child 's prototype references Parents.prototype 's properties. 这里, Child的原型引用了Parents.prototype的属性。 This is what I expected above? 这是我的预期吗?

  2. On the other hand, Sibling 's prototype reference is now a function, which is the prototype reference of Parent . 另一方面, Sibling的原型参考现在是一个函数,它是Parent的原型参考。

Example 3 例3

This seems to be the way to preserve the parent object's prototype reference, but you lose its prototype property. 这似乎是保留父对象的原型引用的方法,但是你丢失了它的原型属性。

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

Is the method shown in Example 1 preferred since you have access to both the parent's prototype property, its own properties as well as Object 's properties/methods? 示例1中显示的方法是首选的,因为您可以访问父级的prototype属性,它自己的属性以及Object的属性/方法吗? I've read in other posts that some of these ways of inheriting should be equal...which is not true. 我在其他帖子中读到,这些继承方式中的一些应该是平等的......这不是真的。 Also, I've read other posts, eg here , that Example 3 is the way to go. 此外,我已阅读其他帖子,例如此处示例3是要走的路。 Or perhaps I am just not sure what __proto__ stands for... 或许我只是不确定__proto__代表什么......

Thanks for any clarification you might have for the differences between these mix and match situations! 感谢您对这些混合和匹配情况之间的差异所做的任何澄清!

I distinguish between the "prototype member" of an object, eg someObject.prototype and the "prototype reference" 我区分对象的“原型成员”,例如someObject.prototype和“原型引用”

Good terminology, and distinguishing them is the first step in understanding them and the difference between them . 良好的术语,区分它们是理解它们的第一步,以及它们之间的区别

(which I think should refer to the object from which someObject inherits?). (我认为应该引用someObject继承的对象?)。

Exactly. 究竟。 In contrast to the .prototype member, you acess the protypte reference via Object.getPrototypeOf(obj) or the non-standard .__proto__ property. .prototype成员相比,您通过Object.getPrototypeOf(obj)或非标准.__proto__属性访问protypte引用。

Example 1 例1

Isn't this the recommended way of inheriting? 这不是推荐的继承方式吗?

It's one way to do inheritance, and the most pure form of prototypical inheritance. 它是继承的一种方式,也是最纯粹的原型继承形式。 Notice that Parent and Child are plain objects, no constructor functions are involved. 请注意, ParentChild是普通对象,不涉及构造函数。

 // create object whose prototype reference is Object; add stuff. var Parent = Object.create(Object); 

That's the first mistake: You're inheriting from the Object function (which is based on the constructor pattern, see below). 这是第一个错误:你继承自Object 函数 (基于构造函数模式,见下文)。 You should just do 你应该这样做

var Parent = {};
// or
var Parent = Object.create(Object.prototype);
 // add stuff to prototype member Parent.prototype.b = 1; Parent.prototype.g = function() { return false; }; 

Yet, the .prototype member is of no significance in this model of inheritance. 然而, .prototype成员在这种继承模型中并不重要。 It's just a normal property, in this case one inherited from Object . 它只是一个普通的属性,在这种情况下,它继承自Object You're actually modifying the Object.prototype object here (big no-no)! 你实际上是在这里修改Object.prototype对象(大Object.prototype )!

 // create an object whose prototype reference is Parent (??) var Child = Object.create(Parent); 

Yes, that's what Object.create does. 是的,这就是Object.create所做的。

[Example 1 / 1] I would have expected Child. [例1/1]我原以为是Child。 proto to be something naming Parent in the same way Parent. proto是以同样的方式命名Parent的东西。 proto names Object. proto names对象。

It names Object only because that is a named function. 它只命名Object因为它是一个命名函数。 There's no way to know the variable name Parent from the object reference at runtime. 在运行时无法从对象引用中知道变量名称Parent

[Example 1 / 2] We see that Child's prototype reference points to the members of Parent rather than the members of Parent.prototype. [例1/2]我们看到Child的原型引用指向Parent的成员而不是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的成员b和g。

Yes, you're directly inheriting from the Parent object. 是的,您直接从Parent对象继承。 .prototype is insignificant as stated above. .prototype是微不足道的。 Child.prototype === Object.prototype (it's inherited twice). Child.prototype === Object.prototype (它继承了两次)。

Example 2 - use a constructor instead. 示例2 - 改为使用构造函数。 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. [例2/1]这里,Child的原型引用了Parents.prototype的成员。 This is what I expected above? 这是我的预期吗?

No. The new operator creates a prototype reference to the value of the .prototype member of the supplied constructor function - Parent.prototype in this case. 否。 new运算符创建对所提供构造函数的.prototype成员的值的原型引用 - 在这种情况下为Parent.prototype

 // create differently var Sibling = Object.create(Parent); 

Again, here you're creating an object that has a prototype reference to a function. 同样,在这里,您要创建一个具有函数原型引用的对象。 Not what you want - instead use 不是你想要的 - 而是使用

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. [例2/2]另一方面,兄弟姐妹的原型参考现在是一个函数,它是Parent的原型参考。

To be more exact, it is the Parent function itself. 更确切地说,它是Parent函数本身。 That's why your Sibling does inherit a .prototype property. 这就是你的Sibling继承了.prototype属性的原因。

Example 3 - This seems to be the way to preserve the parent object's prototype reference, but you lose its prototype member: 示例3 - 这似乎是保留父对象的原型引用的方法,但是您丢失了它的原型成员:

 // supposed Ad-hoc prototype inheritance Child.prototype = Object.create(Parent.prototype) 

This is necessary to set up the inheritance (prototype reference) chain for the constructor way. 这是为构造函数方式设置继承(原型引用)链所必需的。 It's the standard way to implement a "class" pattern in JavaScript. 这是在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) // {} 

As you see here, both Parent and Child are functions - constructor functions to be exact. 如您所见, ParentChild都是函数 - 准确的构造函数。 You would need to invoke them: 你需要调用它们:

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

However, you forgot one step. 但是,你忘记了一步。 childInstance does inherit b and g from Parent.prototype , but does not have the a and f proeprties created in the Parent constructor. childInstance确实从Parent.prototype继承了bg ,但没有在Parent构造函数中创建的af proeprties。 For correct inheritance in the constructor model you also have to apply the Parent constructor on each instance, preferably inside the Child constructor: 为了在构造函数模型中进行正确的继承,您还必须在每个实例上应用Parent构造函数,最好是在Child构造函数中:

function Child() {
    Parent.call(this);
    this.c = "2";
}
var childInstance = new Child();
console.log(childInstance) // {a: 1, f: [Function …], c: "2"}

To understand what Object.create does, first you need to understand why it needs to do it. 要了解Object.create作用,首先需要了解它为什么需要这样做。

The classic examples of prototyping in JavaScript makes the prototype be an instance of the inherited object: 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; }

That "oops" line makes Child.prototype have a field , when we wanted it to only inherit the method getField . 那个“oops” Child.prototype有一个field ,当我们希望它只继承方法getField You can guess this is not hygienic (language-wise), and it can get messy with less trivial examples. 你可以猜测这不是卫生的(语言方面的),并且可能会因为不那么重要的例子而变得混乱。

A cleaner approach would be to instantiate a non-initialized Parent : 更简洁的方法是实例化一个未初始化的Parent

function inherit(parent) {
    function temp() {
    }
    temp.prototype = parent.prototype;
    return new temp();
}

Child.prototype = inherit(Parent);

The technique is to make a temporary constructor with the same prototype, such that when an object is created, no constructor initializations were done. 该技术是使用相同的原型制作临时构造函数,这样在创建对象时,不会进行构造函数初始化。 Effectively, only the prototype chain has been established. 实际上,只建立了原型链。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM