1. ホーム
  2. javascript

[解決済み] RequireJS/AMDで循環依存性を処理する方法とは?

2023-07-31 22:23:56

質問

私のシステムでは、いくつかのクラスがブラウザに読み込まれ、開発中はそれぞれ別のファイルであり、本番では一緒に結合されるようになっています。それらが読み込まれると、グローバル オブジェクトのプロパティが初期化されます。 G この例のように。

var G = {};

G.Employee = function(name) {
    this.name = name;
    this.company = new G.Company(name + "'s own company");
};

G.Company = function(name) {
    this.name = name;
    this.employees = [];
};
G.Company.prototype.addEmployee = function(name) {
    var employee = new G.Employee(name);
    this.employees.push(employee);
    employee.company = this;
};

var john = new G.Employee("John");
var bigCorp = new G.Company("Big Corp");
bigCorp.addEmployee("Mary");

独自のグローバルオブジェクトを使用する代わりに、各クラスを独自の AMDモジュール をベースにして James Burke の提案 :

define("Employee", ["Company"], function(Company) {
    return function (name) {
        this.name = name;
        this.company = new Company(name + "'s own company");
    };
});
define("Company", ["Employee"], function(Employee) {
    function Company(name) {
        this.name = name;
        this.employees = [];
    };
    Company.prototype.addEmployee = function(name) {
        var employee = new Employee(name);
        this.employees.push(employee);
        employee.company = this;
    };
    return Company;
});
define("main", ["Employee", "Company"], function (Employee, Company) {
    var john = new Employee("John");
    var bigCorp = new Company("Big Corp");
    bigCorp.addEmployee("Mary");
});

問題は、以前は Employee と Company の間に宣言時の依存関係がなかったことです。つまり、好きな順序で宣言を配置することができましたが、現在 RequireJS を使用して、これは依存関係を導入し、ここでは(意図的に)循環しているので、上記のコードは失敗します。もちろん addEmployee() を追加すると、最初の行 var Employee = require("Employee"); を追加すると しかし、この解決策は、RequireJS/AMDを使用しない場合よりも劣っていると私は考えています。

RequireJS/AMD でこの問題を解決する良い方法はありますか?それとも、私は RequireJS/AMD をそのために設計されていないもののために使っていますか?

どのように解決するのですか?

これは確かにAMD形式の制約です。エクスポートを使えば、この問題は解消されます。私はexportsは醜いと思っていますが、通常のCommonJSモジュールが問題を解決する方法です。

define("Employee", ["exports", "Company"], function(exports, Company) {
    function Employee(name) {
        this.name = name;
        this.company = new Company.Company(name + "'s own company");
    };
    exports.Employee = Employee;
});
define("Company", ["exports", "Employee"], function(exports, Employee) {
    function Company(name) {
        this.name = name;
        this.employees = [];
    };
    Company.prototype.addEmployee = function(name) {
        var employee = new Employee.Employee(name);
        this.employees.push(employee);
        employee.company = this;
    };
    exports.Company = Company;
});

その他、メッセージにあるrequire("Employee")もうまくいくでしょう。

一般的に、モジュールでは、AMDであろうとなかろうと、循環的な依存関係をより認識する必要があります。プレーンなJavaScriptであっても、あなたの例のGオブジェクトのようなオブジェクトを確実に使用する必要があります。