有条件地延长当前class
Conditionally extend the current class
我想要一个 JavaScript class,它可以有条件地从单独的文件中向自身添加其他方法。这个想法是将应用程序的不同关注点分离到更易于管理的独立模块中,这些模块仍然可以与母应用程序中的方法进行交互 class。因此,单独文件中的附加方法必须能够引用主文件中的方法和变量class。请参阅下面的代码示例。
我查看了很多不同的解决方案,但它们都对我想要的有不利影响。
- 我可以
new Uploads()
,但我找不到方法让 Uploads.js
中的方法引用主要 App
class 中的方法
- 我可以使用
extends
,但这不允许有条件的扩展 AFAIK
- I could just define new methods into the prototype itself,但这意味着外部文件需要“知道”class 它将在其中使用,这并不能使其广泛重用。
到目前为止我最好的是:
app.js
const Uploads = require("./Uploads.js");
const config = { hasUploads: true }; // Probably loaded from a file
class App {
constructor() {
/* Only include the separate module if the config says so */
if(config.hasUploads) {
Object.assign(this, Uploads);
}
}
foo() {
/* Something */
}
}
Uploads.js
module.exports = {
bar() {
this.foo();
}
};
可行,但我不知道这是否是最佳解决方案;
- 没有构造函数,所以如果
Uploads.js
需要做一些设置,app.js
需要包含这样做的逻辑(或者至少知道调用一些唯一命名的人造构造函数方法),这似乎不太理想。
- 如果
Uploads.js
包含与 app.js
或任何其他可能正在加载的模块同名的方法,它们将被覆盖,导致意外行为。
Uploads.js
是一个函数对象,而app.js
定义了一个class。 理想情况下(尽管我想不一定)为了代码的可管理性,它们应该使用相同的语法。
有没有 better/cleaner/nicer 的方法?
修复从上传文件覆盖现有方法的一个选项是在循环中分配新方法并检查重复项(Object.assign
在这种情况下并不理想)并且只添加一次更新:
const Uploads = {
bar() {
this.foo("called from bar");
}
};
const config = { hasUploads: true, // Probably loaded from a file
configured: false
};
class App {
constructor() {
/* Only include the separate module if the config says so */
if(config.hasUploads && !config.configured) {
const proto = this.constructor.prototype;
const methods = Object.keys(Uploads);
methods.forEach( name=> {
if( proto[ name] ) {
throw new Error( "App already has method " + name);
}
proto[name] = Uploads[name];
});
config.configured = true;
}
}
foo(arg) {
/* Something */
console.log( arg );
}
}
const app = new App();
app.bar();
更好(更干净)的替代方法可能是在调用其构造函数之前向 class 添加更新,使用静态 class 方法,因为其 this
值是构造函数。测试示例:
static addMethods(uploads) { // inside class declaration
const proto = this.prototype;
for (const [name, method] of Object.entries(uploads)) {
if( proto[name]) {
throw new Error("App already has a ${name} method");
}
proto[name] = method;
}
}
根据需要由
调用
if( config.hasUploads) {
App.addMethods( Uploads);
}
与其尝试执行某种疯狂的多重继承,不如尝试拥抱组合?非常适合解决这类问题
class App {
constructor(modules) {
if (modules.uploads) {
this.uploads = modules.uploads(this);
}
}
foo() {
console.log('foo!');
}
}
class Uploads {
constructor(context) {
this.context = context;
}
method() {
this.context.foo();
}
}
const app = new App({ uploads: (ctx) => new Uploads(ctx) });
app.uploads.method();
您可以非常喜欢这个并使用构建器来配置具有特定类型模块的应用程序。
根据您预期的复杂性,您可能需要考虑使用 event buses
、mediators
或 commands
将事物与主机本身分离。
我想要一个 JavaScript class,它可以有条件地从单独的文件中向自身添加其他方法。这个想法是将应用程序的不同关注点分离到更易于管理的独立模块中,这些模块仍然可以与母应用程序中的方法进行交互 class。因此,单独文件中的附加方法必须能够引用主文件中的方法和变量class。请参阅下面的代码示例。
我查看了很多不同的解决方案,但它们都对我想要的有不利影响。
- 我可以
new Uploads()
,但我找不到方法让Uploads.js
中的方法引用主要App
class 中的方法
- 我可以使用
extends
,但这不允许有条件的扩展 AFAIK - I could just define new methods into the prototype itself,但这意味着外部文件需要“知道”class 它将在其中使用,这并不能使其广泛重用。
到目前为止我最好的是:
app.js
const Uploads = require("./Uploads.js");
const config = { hasUploads: true }; // Probably loaded from a file
class App {
constructor() {
/* Only include the separate module if the config says so */
if(config.hasUploads) {
Object.assign(this, Uploads);
}
}
foo() {
/* Something */
}
}
Uploads.js
module.exports = {
bar() {
this.foo();
}
};
可行,但我不知道这是否是最佳解决方案;
- 没有构造函数,所以如果
Uploads.js
需要做一些设置,app.js
需要包含这样做的逻辑(或者至少知道调用一些唯一命名的人造构造函数方法),这似乎不太理想。 - 如果
Uploads.js
包含与app.js
或任何其他可能正在加载的模块同名的方法,它们将被覆盖,导致意外行为。 Uploads.js
是一个函数对象,而app.js
定义了一个class。 理想情况下(尽管我想不一定)为了代码的可管理性,它们应该使用相同的语法。
有没有 better/cleaner/nicer 的方法?
修复从上传文件覆盖现有方法的一个选项是在循环中分配新方法并检查重复项(Object.assign
在这种情况下并不理想)并且只添加一次更新:
const Uploads = {
bar() {
this.foo("called from bar");
}
};
const config = { hasUploads: true, // Probably loaded from a file
configured: false
};
class App {
constructor() {
/* Only include the separate module if the config says so */
if(config.hasUploads && !config.configured) {
const proto = this.constructor.prototype;
const methods = Object.keys(Uploads);
methods.forEach( name=> {
if( proto[ name] ) {
throw new Error( "App already has method " + name);
}
proto[name] = Uploads[name];
});
config.configured = true;
}
}
foo(arg) {
/* Something */
console.log( arg );
}
}
const app = new App();
app.bar();
更好(更干净)的替代方法可能是在调用其构造函数之前向 class 添加更新,使用静态 class 方法,因为其 this
值是构造函数。测试示例:
static addMethods(uploads) { // inside class declaration
const proto = this.prototype;
for (const [name, method] of Object.entries(uploads)) {
if( proto[name]) {
throw new Error("App already has a ${name} method");
}
proto[name] = method;
}
}
根据需要由
调用 if( config.hasUploads) {
App.addMethods( Uploads);
}
与其尝试执行某种疯狂的多重继承,不如尝试拥抱组合?非常适合解决这类问题
class App {
constructor(modules) {
if (modules.uploads) {
this.uploads = modules.uploads(this);
}
}
foo() {
console.log('foo!');
}
}
class Uploads {
constructor(context) {
this.context = context;
}
method() {
this.context.foo();
}
}
const app = new App({ uploads: (ctx) => new Uploads(ctx) });
app.uploads.method();
您可以非常喜欢这个并使用构建器来配置具有特定类型模块的应用程序。
根据您预期的复杂性,您可能需要考虑使用 event buses
、mediators
或 commands
将事物与主机本身分离。