使用纯Prototypal方法在Javascript中的寄生继承

时间:2015-06-23 07:50:49

标签: javascript oop inheritance

我正在使用JavaScript学习OOP,并且已经在同一篇文章中经历了各种各样的帖子。据我所知,道格拉斯·克罗克福德(Douglas Crockford)规定了继承pure prototypal approach而不是经典方法。

以下代码来自here,实现了Crockford的方法:

.content {
	width: 100%;
	height: 100%;
	display: table;
	border-spacing: 10px;
}

#fullwidthcontent {
	z-index: -1;
	width: 75%;
	min-width: 600px;
	border-radius: 20px;
	background-color: #000000;
	opacity: 0.7;
	height: 86%;
	padding-left: 50px;
	padding-right: 30px;
	position: fixed;
	left: 210px;
	top: 15px;	
	overflow: auto;
}

.fullwidthoverlay {
	z-index:9999;
	width: 75%;
	min-width: 600px;
	height: 60%;
	opacity: 1;
	padding-left: 50px;
	padding-right: 30px;
	position: fixed;
	left: 210px;
	top: 145px;	
	overflow: auto;
}

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

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

感谢。

1 个答案:

答案 0 :(得分:2)

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

  1. 永远不要直接在原型中定义字段成员。
  2. 实例化后继者
  3. 时始终调用基础构造函数

    后者可以使用Object.create实现一个人的品味,或者直接将基础对象的实例分配给原型。鉴于Base是构造函数,继承的代码将如下所示 方式#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');
     };
    

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

    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
    

    注意通过successorMethod定义的遗失Successor.prototype。发生这种情况是因为我们已经覆盖了对象的__proto__属性。

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

     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
     }
    

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

    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,尽管它是在构造函数中为this定义的。这可能是错误的来源。

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

     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内定义

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

    实例(child)将无法访问等于“我是父母”的baseIntance.baseMember。与以前的方法相反,它可以通过child.__proto__.baseMember访问。但我相信这在javascript开发时并不常见,应该包含在另一个问题中。

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

    <强>结论
    我希望这个描述足够清楚,以便理解 Cra Crockford的object函数

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

    始终需要将新实例作为参数o传递,以实现寄生继承。因此它的用法应如下所示

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

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

    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());
    

    希望这有帮助