有条件地延长当前class

Conditionally extend the current class

我想要一个 JavaScript class,它可以有条件地从单独的文件中向自身添加其他方法。这个想法是将应用程序的不同关注点分离到更易于管理的独立模块中,这些模块仍然可以与母应用程序中的方法进行交互 class。因此,单独文件中的附加方法必须能够引用主文件中的方法和变量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();
    }
};

可行,但我不知道这是否是最佳解决方案;

有没有 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 busesmediatorscommands 将事物与主机本身分离。