使用纯Prototypal方法在Javascript中的寄生继承 [英] Parasitic Inheritance in Javascript using pure Prototypal approach

查看:92
本文介绍了使用纯Prototypal方法在Javascript中的寄生继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaScript学习OOP并且已经在同一个帖子上进行过各种各样的帖子。据我所知,Douglas Crockford规定了纯粹的原型方法来继承,而不是经典方法。

I am learning OOP in JavaScript and have gone through various posts on the same. It has come to my knowledge that Douglas Crockford prescribes a pure prototypal approach to inheritance as opposed to the classical approach.

以下代码取自这里实现了Crockford的方法:

The following code taken from here implements Crockford's method:

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';

我知道Crockford的方法取消了构造函数(如果我错了,请纠正我)。这是否意味着使用此方法初始化对象成员的唯一方法是使用上面代码中所示的对象文字?此外,如何使用此方法实现 寄生继承 以允许父类中的共享成员,私有变量和非标量值(参考这篇文章)?

I understand that Crockford's approach does away with constructor functions (correct me if I am wrong). Does this mean that the only way to initialize object members with this approach is by using object literals as shown in above code? Also, how do I implement parasitic inheritance with this approach to allow shared members, private variables and non-scalar values in the parent class (refer this post)?

Crockford在他的文章中提到制造商功能,但没有提供任何示例代码。如果有人能够使用Crockford纯粹的原型方法证明寄生遗传,那就太棒了。

Crockford mentions "maker functions" in his article, but does not give any example code for it. It would be great if someone could demonstrate parasitic inheritance using Crockford's pure prototypal approach.

谢谢。

推荐答案

对原型继承的误解源于这样一个问题,即与经典继承相反,基础构造函数不会被调用来实例化基础对象。将原型设置为基础对象并不等同于经典继承,因为原型在实例之间共享。正如Jimmy Breck-McKye所详述。因此,要实现寄生继承,您必须遵循两个规则。

Misunderstanding about prototypal inheritance arise from the problem that in contrary to classical inheritance base constructor is not called to instantiate base object. Setting prototype to base object is not equivalent to classical inheritance, because prototype is shared among instances. As described in detail by Jimmy Breck-McKye. So to achieve parasitic inheritance you will have to follow two rules.


  1. 永远不要直接在原型中定义字段成员。

  2. 在实例化后继者时总是调用基础构造函数

后者可以用一个人的口味来实现 Object.create 或直接将基础对象的实例分配给原型。鉴于 Base 是一个构造函数,继承代码如下所示:
方式#1

The latter can be achieved to one's taste using Object.create or assigning instance of base object directly to prototype. Given that Base is a constructor function, code for inheritance will be like below
Way #1

 function Base(){
 //a new object is created which is assigned to 'this'
 //this object has __proto__ === Base.prototype
     this.baseMember = 'I am the parent';
 }
 Base.prototype.baseMethod = function(){
     console.log('I am Base');
 };

 function Successor(){
 //a new object is created which is assigned to 'this'
 //this object has __proto__ === Successor.prototype

 //we override the object's property which is used for prototypal lookup
 //we lose members defined in Successor.prototype
      this.__proto__ = new Base();
 //we add a new property in the inherited object
      this.successorMember = 'I am a child';
 }
 Successor.prototype.successorMethod = function(){
     console.log('I am Successor');
 };

我们将按以下方式使用定义的构造函数

We will use defined constructor in the following manner

var child = new Successor();
//resulting in structure
//child: { //instance of Successor
//  successorMember: 'I am a child', 
//  __proto__: {//instance of Base
//     baseMember: 'I am the parent'
//     __proto__: {//Base.prototype
//        baseMethod : function 
//  }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

注意通过 Successor.prototype successorMethod $ C>。这是因为我们已经覆盖了对象的 __ proto __ 属性。

Pay attention to the missing successorMethod defined via Successor.prototype. This happened because we've overridden __proto__ property of the object.

方式#2

覆盖 __proto __ 属性的另一种方法是调用 Object.create 。但是这个函数返回一个新对象,因此我们必须覆盖 Successor 构造函数返回的对象

Way #2
Another way to override the __proto__ property is to call Object.create. However this function returns a new object and thus we will have to override the object that is returned by Successor constructor

 function Successor(){
 //a new object #1 is created which is assigned to 'this'
 //this object has __proto__ === Successor.prototype

 //a new instance #2 of Base is created with __proto__ === Base.prototype
 //a new object #3 is created with a __proto__ set to #2
      var successor = Object.create(new Base());
 //a new property is added to #1
      this.neverShowMember = 'I will not exist in resulting object';
 //a new property is added to #3 
      successor.successorMember = 'I am a child';
 //return of a non-primitive type object from constructor overrides the result
      return successor;//return object #3
 }

让我们详细研究一下这种方法的用法:

Let's examine usage of this approach in detail:

var child = new Successor();
//child: { //instance of Object
//  successorMember: 'I am a child', 
//  __proto__: {//instance of Base
//     baseMember: 'I am the parent'
//     __proto__: {//Base.prototype
//        baseMethod : function 
//  }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

结果行为几乎相同。注意缺少的 neverShowMember 虽然它是在构造函数中为定义的。它可能是错误的来源。

Resulting behaviour is pretty much the same. Pay attention to the missing neverShowMember although it was defined for this within constructor. It may be source of mistakes.

方式#3

另一种继承方式是不要乱用 proto 链。这种方法在Jimmy Breck-McKye的文章中有所描述。我将跳过之前提供的详细评论,并将重点关注更改

Way #3
Yet another way to inherit is not to mess around with proto chains. This approach is described in Jimmy Breck-McKye's article. I will skip detailed comments which were provided previously and will focus on changes

 function Successor(){
 //a new instance  Base is created with __proto__ === Base.prototype
      var successor = new Base();
 //extend object with a new property 
      successor.successorMember = 'I am a child';
      return successor;//return instance of Base with extra properties
 }

 var child = new Successor();
//child: { //instance of Base
//  successorMember: 'I am a child', 
//  baseMember: 'I am the parent'
//  __proto__: {//Base.prototype
//        baseMethod : function 
//  }} 
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via direct property
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

您会看到架构变得扁平。作为一个明显的结论,如果覆盖它们,则无法访问基本成员。因此,如果在 Successor 内,我们定义

You see that schema became flat. As an obvious conclusion you can't access base members if you override them. So if inside Successor we define

successor.baseMember = 'I am already grown enough!';

实例( child )将失去访问权限到 baseIntance.baseMember 等于我是父母。与之前的方法相反,它可以通过 child .__ proto __。baseMember 访问。但是我相信这在javascript中开发并不是常见的情况,应该包含在另一个问题中。

The instance (child) will lose access to baseIntance.baseMember which equals "I am the parent". In contrary to previous approaches when it would be accessible via child.__proto__.baseMember. But I believe this is not a common scenario when developing in javascript and should covered under another question.

注意在所有情况下成员定义 Successor.prototype 丢失了。您应该在 Successor 构造函数中手动复制它们。

Note that in all cases members defined in Successor.prototype are lost. You should take care of copying them manually in Successor constructor.

结论

我希望这个描述足够清楚,以了解 Cra Crockford的对象函数

Conclusion
I hope this description was clear enough to understand that CraCrockford's object function

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

总是需要传递一个新实例作为参数 o 实现寄生继承。因此它的用法应如下所示

always requires a new instance passed as parameter o to achieve parasitic inheritance. Thus it's usage should look like below

var child = object(new Base());
child.successorMember = 'I am a child';

同样适用于OP的代码。要跟随寄生继承 superInstance ,每次传递给 Object.create 。因此它应该是一个工厂函数

Same applies to the code from OP. To follow parasitic inheritance superInstance should be a new instance each time it is passed to Object.create. Thus it should be a factory function

var superInstance = function(){
    return {
      member1: 'superMember1',
      member2: 'superMember2'
    }
};

var subInstance = Object.create(superInstance());

或构造函数

function superInstance(){
    this.member1: 'superMember1',
    this.member2: 'superMember2'
};

var subInstance = Object.create(new superInstance());

希望这会有所帮助

这篇关于使用纯Prototypal方法在Javascript中的寄生继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆