【问题标题】:Objects don't inherit prototyped functions对象不继承原型函数
【发布时间】:2012-06-19 19:34:03
【问题描述】:

我有一个构造函数,它充当超类:

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

我将其原型化为包含一个简单的方法:

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

现在新的Bla(1).f(); 将在控制台中记录“f”。但是,假设我需要一个继承自 Bla 的子类:

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

x = new Bla2(5);

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

【问题讨论】:

  • 它正在发生,因为您的代码中没有任何内容安排它不会发生。如果您认为设置一个名为“base”的属性会使一个类从另一个类继承,那是不正确的。
  • 感谢格式化,@MarkLinus!
  • 尝试将Bla2.prototype 设置为new Bla()
  • 好吧,但是调用基应该将构造函数中的“this”设置为指向我的对象,对吧?那么,我该如何以正确的方式做到这一点?
  • @T.J.Crowder 是的,我意识到这一点;像往常一样,您提供的答案超出了全面性:-) 我发现自己很少编写这样的代码,以至于我不相信自己会尝试真正的答案。

标签: javascript oop inheritance prototype


【解决方案1】:

好像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 来获取每个实例的初始化。

以上内容非常基础,如您所见,涉及多个步骤。它也很少或根本没有使“超级调用”变得容易和高度可维护。这就是为什么你会看到这么多“继承”脚本,比如 Prototype 的 Class、Dean Edwards 的 Base2 或 (咳)我自己的 Lineage


如果您不能依赖在您的环境中拥有 ES5 功能,并且不想包含执行 Object.create 基本功能的 shim,则可以使用此函数代替它:

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。所以我倾向于在每个“类”(构造函数和相关原型)周围使用模块模式并使用函数 declarations(因为我确实为 web 工作,而 IE7 和 IE8 still have problems 带有命名函数表达式。所以如果我不使用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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-08
    • 2022-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 2014-11-26
    相关资源
    最近更新 更多