2012-06-17 55 views
5

我有一个构造函数,它作为一个超:对象不继承原型的功能

Bla = function(a){this.a = a;} 

我样机它包括一个简单的方法:

Bla.prototype.f = function(){console.log("f"); 

而现在新Bla(1).f();会在控制台中登录“f”。但是,可以说,我需要从布拉继承的子类:

Bla2 = function(a) 
{ 
    this.base = Bla; 
    this.base(); 
} 

x = new Bla2(5); 

现在,符合市场预期,x.a给我5。但是,x.fundefined!好像Bla2没有从Bla类继承它!为什么会发生这种情况,我该如何纠正?

+2

它的发生是因为没有在你的代码安排它*不*发生。如果你认为设置一个名为“base”的属性会使一个类继承另一个类,那么这是不正确的。 – Pointy

+1

感谢格式化,@MarkLinus! – corazza

+1

尝试将'Bla2.prototype'设置为'new Bla()'。 – Pointy

回答

28

好像Bla2没有从Bla类继承它!

没错。你没有做任何事情来连接那里的继承,你刚刚创建了一个名为baseBla2成员,它是一个Bla实例。 base不是JavaScript中的特殊标识符。

设立继承JavaScript中的典型方式是这样的:

// The base constructor function 
function Base(x) { 
    // Base per-instance init 
    this.x = x; 
} 

// An example Base function 
Base.prototype.foo = function() { 
    console.log("I'm Base#foo, x = " + this.x); 
}; 

// The Derived constructor function 
function Derived(x, y) { 
    // Normally you need to call `Base` as it may have per-instance 
    // initialization it needs to do. You need to do it such that 
    // within the call, `this` refers to the current `this`, so you 
    // use `Function#call` or `Function#apply` as appropriate. 
    Base.call(this, x); 

    // Derived per-instance init 
    this.y = y; 
} 

// Make the Derived.prototype be a new object backed up by the 
// Base.prototype.  
Derived.prototype = Object.create(Base.prototype); 

// Fix up the 'constructor' property 
Derived.prototype.constructor = Derived; 

// Add any Derived functions 
Derived.prototype.bar = function() { 
    console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y); 
}; 

...其中Object.create是ES5,但它是可以很容易地大多匀的事情之一。 (或者你可以使用一个函数,只做最低限度,但不尝试做所有的Object.create;见下文)。然后你使用它:

var d = new Derived(4, 2); 
d.foo(); // "I'm Base#foo, x = 4" 
d.bar(); // "I'm Derived#bar, x = 4, y = 2" 

Live example | source

在旧的代码,你有时会看到Derived.prototype设立这样反而:

Derived.prototype = new Base(); 

......但有一个问题,做这样的说法:Base可以做到每个实例的初始化这是不适合整个Derived继承。它甚至可能需要参数(因为我们的Base会;我们会通过x?)。通过改为使Derived.prototype成为由Base.prototype支持的新对象,我们得到了正确的东西。然后我们从Derived中调用Base来获取每个实例的init。

以上是非常基本的,你可以看到涉及一些步骤。它也很少或根本没有使“超级电话”容易和高度维护。这就是为什么你会看到那么多“继承”脚本,比如Prototype的Class,Dean Edwards的Base2或(咳嗽)我自己的Lineage


如果不能依靠在你的环境中ES5功能,并且不希望包括垫片,做的Object.create的基础知识,你可以使用此功能在它的地方:

function simpleCreate(proto) { 
    function Ctor() { 
    } 
    ctor.prototype = proto; 
    return new Ctor(); 
} 

然后,而不是

Derived.prototype = Object.create(Base.prototype); 

你会怎么做:

Derived.prototype = simpleCreate(Base.prototype); 

当然,你可以做更多的事情来自动化连接  —这基本上都是Lineage


...最后:上面我已经用于简单的匿名功能,例如:

Base.prototype.foo = function() { 
    // ... 
}; 

...但我不这样做,在我真正的代码,因为I like to help my tools help me。所以我倾向于在每个“类”(构造函数和相关的原型)周围使用模块模式,并使用函数声明(因为我确实为web,IE7和IE8 still have problems使用了命名函数表达式。所以如果我不' T使用Lineage,我会做上述这样的:

// Base 
(function(target) { 
    // Base constructor 
    target.Base = Base; 
    function Base(x) { 
     // Base per-instance init 
     this.x = x; 
    } 

    // An example Base function 
    Base.prototype.foo = Base$foo; 
    function Base$foo() { 
     console.log("I'm Base#foo, x = " + this.x); 
    } 
})(window); 

// Derived 
(function(target, base) { 
    // The Derived constructor function 
    target.Derived = Derived; 
    function Derived(x, y) { 
     // Init base 
     base.call(this, x); 

     // Derived per-instance init 
     this.y = y; 
    } 

    // Make the Derived.prototype be a new object backed up by the 
    // Base.prototype.  
    Derived.prototype = Object.create(base.prototype); 

    // Fix up the 'constructor' property 
    Derived.prototype.constructor = Derived; 

    // Add any Derived functions 
    Derived.prototype.bar = Derived$bar; 
    function Derived$bar() { 
     console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y); 
    } 
})(window, Base); 

...或者类似的东西Live copy | source

+6

结构良好,非常丰富的答案。 +1 – Kaii