如何扩展JavaScript中闭包后面定义的类?

如何扩展JavaScript中闭包后面定义的类?,javascript,Javascript,我有一组JavaScript“类”,其中一个基类定义了一个继承类共享的函数。它正在工作,设置如下: var ThingA = function(name) { this.name = name; }; ThingA.prototype = { sayHi: function() { alert('Hi, ' + this.name + '!'); } }; var ThingB = function() { ThingA.call(this,

我有一组JavaScript“类”,其中一个基类定义了一个继承类共享的函数。它正在工作,设置如下:

var ThingA = function(name) {
    this.name = name;
};

ThingA.prototype = {
    sayHi: function() {
        alert('Hi, ' + this.name + '!');
    }
};


var ThingB = function() {
    ThingA.call(this, 'Charlie');
};

ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;

var instanceOfB = new ThingB();
instanceOfB.sayHi();   // alerts 'Hi, Charlie!'
FactoryClassA = function() {

    var ThingA = function(name) {
        this.name = name;
    };

    ThingA.prototype = {
        sayHi: function() {
            alert('Hi, ' + this.name + '!');
        }
    };

    return {
         createThingA: function(name) {
             return new ThingA(name);
         }
    };
}();


FactoryClassB = function() {

    // Define a ThingB class that inherits from ThingA somehow

    return {
         createThingB: function() {
             return new ThingB();
         }
    };
}();


var instanceOfB = FactoryClassB.createThingB();
instanceOfB.sayHi();   // should alert 'Hi, Charlie!'
出于我无法控制的原因,我的公司在编写JavaScript时更喜欢遵循以下模式:

SomeClass = function() {

    // "Private" functions go here

    function somePrivateMethod() { 
        ...
    }

    return {

        // "Public" methods go here
        somePublicMethod: function() { ... }

    };
}();
现在,就目前情况而言,这很好,在很多情况下都很有效。但它更多的是一种功能性风格。只有一个“类”实例,所有的东西都是静态的

我被要求修改我的工作代码,使之更符合我的公司喜欢的风格。所以我的问题是,有没有一种方法可以从封装在工厂类中的类继承?它看起来像这样:

var ThingA = function(name) {
    this.name = name;
};

ThingA.prototype = {
    sayHi: function() {
        alert('Hi, ' + this.name + '!');
    }
};


var ThingB = function() {
    ThingA.call(this, 'Charlie');
};

ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;

var instanceOfB = new ThingB();
instanceOfB.sayHi();   // alerts 'Hi, Charlie!'
FactoryClassA = function() {

    var ThingA = function(name) {
        this.name = name;
    };

    ThingA.prototype = {
        sayHi: function() {
            alert('Hi, ' + this.name + '!');
        }
    };

    return {
         createThingA: function(name) {
             return new ThingA(name);
         }
    };
}();


FactoryClassB = function() {

    // Define a ThingB class that inherits from ThingA somehow

    return {
         createThingB: function() {
             return new ThingB();
         }
    };
}();


var instanceOfB = FactoryClassB.createThingB();
instanceOfB.sayHi();   // should alert 'Hi, Charlie!'
有没有一种方法可以定义
封装在
FactoryClassB
中的
ThingB
是从
封装在
FactoryClassA
中的
ThingA
继承来的?
多亏了,我知道我不能完全这样做。我正在考虑使用一种方法来扩展给定的类。。。不知怎么的

似乎很接近,但我很难找出如何修改该示例以适应我的具体情况的细节。我愿意稍微改变一下公司的常规模式,但我至少能更接近它吗

更新1

作为对Adam关于只向factory类添加一个参数的评论的回应,下面是我遇到的问题:

ThingB.prototype = new ThingA();
ThingB.prototype.constructor = ThingB;
如果我只是将一个参数传递给factory类方法,我不知道如何调整这些行以使其工作。

下面是(我相信)您正在寻找的:

FactoryClassA = function() {
    var ThingA = function(name) {
       this.name = name;
    };
    ThingA.prototype = {
        sayHi: function() {
            console.log('Hi, ' + this.name + '!');
        }
    };
    // Add the constructor back to the prototype
    // (see explanation below)
    ThingA.prototype.constructor = ThingA;

    return {
        createThingA: function(name) {
            return new ThingA(name);
        }
    };
}();

FactoryClassB = function() {
    // Bootstrapping:
    // Capture the instance, as we'll need it to set up the prototype
    var baseInstance = new FactoryClassA.createThingA();
    // Capture the constructor
    var baseConstructor = baseInstance.constructor;
    // Keep a reference to the base prototype
    var baseProto = baseConstructor.prototype;

    function ThingB(name) {
        // Call base constructor, along with our args
        baseConstructor.call(this, name);
    };
    ThingB.prototype = baseInstance;
    ThingB.prototype.constructor = ThingB;

    ThingB.prototype.sayHi = function() {
        console.log('here I am');
        // call the base class `sayHi`
        baseProto.sayHi.call(this);
    };

    return {
        createThingB: function(name) {
            return new ThingB(name);
        }
    };
}();

// Testing
var foo = FactoryClassB.createThingB("Indeed");
foo.sayHi();

// Output:
//   here I am 
//   hi indeed
说明

FactoryClassA
中,此行是必需的:

ThingA.prototype.constructor = ThingA;
请注意,JS中的每个原型都是通过引用其构造函数自动创建的。例如,当您执行以下操作时:

function T(){}
T.prototype
已经有一个名为
constructor
的属性,它指向
T

但是,在
ThingA
的实现中,通过执行
ThingA.prototype={…}
重置整个原型。因此,您现在失去了对其构造函数的引用。在99%的情况下,它是可以的,并且不会有任何负面影响(这可能是大多数开发人员倾向于忘记它的原因)。然而,在继承的情况下,它可能是必要的

现在,在
FactoryClassB
中,我们需要进行一些引导:

var baseInstance = new FactoryClassA.createThingA();
var baseConstructor = baseInstance.constructor;
var baseProto = baseConstructor.prototype;
观察最后两行,因为它们对于在这个设计模式中实现继承至关重要。首先,由于可以通过原型(
ThingA.prototype.constructor=ThingA
)访问
ThingA
的构造函数,因此这意味着给定
ThingA
的实例,我们可以直接检索其构造函数。由于构造函数就是函数本身,而且每个函数都有一个对其原型的引用,因此我们可以使用
baseConstructor.prototype
保留
ThingA.prototype
的引用

接下来是关键部分,我们在其中设置继承链:

function ThingB(name) {
    // Call the base constructor
    baseConstructor.call(this, name);
};
ThingB.prototype = baseInstance;
ThingB.prototype.constructor = ThingB;
上面的最后一行非常重要,因为它告诉原型它的构造函数是什么,否则它仍然会指向
ThingA

这就是原型遗传

旁注


您可能会看到上面的内容是如何变得相当乏味、有点怪异和重复的。ErGo,你可能想考虑一个继承类库,它遵循你想要的封装模式(还有一些像混合和装饰器之类的奖金)。免责声明:我编写了该库。

代码运行良好:
FactoryClass A
的定义以
()结尾请参见
FactoryClass A{…}()
。它是函数还是对象?啊,谢谢。我无法对此进行测试,因为FactoryClass示例实际上还不起作用——这正是我试图实现的。让我来更新一下……主持人注:请在评论中友好一些。非建设性意见将被删除。这是一个很好的解释。我已经非常接近这个解决方案,但却遗漏了几个关键点。非常感谢你!