十分に複雑なプロジェクトでは、機能を可能な限り切り離す必要があります。
デカップリングとは何ですか?簡単に言えば、モジュールを形成するには、さまざまな機能をさまざまなファイルまたはさまざまなディレクトリ構造に分割する必要があります。モジュールは限られたインターフェイスを介して相互に作用し、モジュール内のデータ変更は外部から隠されます。
ノードでは、これは非常に優れています。NodeはCommonJS仕様を実装し、各JSファイルはモジュールであり、モジュール内のすべてのデータは、モジュールModule.exports
内のコンテンツを公開することによってのみ、外部に隠されます。
したがって、モジュール開発はノード環境ではもはや問題ではありません。
ただし、JS言語はノード環境だけでなく、非常に重要で非常に一般的な動作環境であるクライアントブラウザーも実行できます。
以前は、JSがクライアントで行ったことは非常に単純で、大まかに次のようになりました。
- アニメーション効果
- フォームの検証
- 少数のajaxリクエスト
ただし、フロントエンド環境の変化に伴い、フロントエンドとバックエンドの分離開発がますます一般的になっています。これまでのところ、インターネット企業のバックエンド開発者のほとんどは、データインターフェイス(REST API)を提供するだけで済みます。 、およびその他ユーザーを扱うすべてのことは、フロントエンドで完了する必要があります。
その結果、フロントエンド開発の複雑さが突然増しました。今度は、フロントエンド開発者は次のことを完了する必要があります。
- アニメーション効果
- フォームの検証
- 多数のajaxリクエスト
- ウェブサイト全体のページ構成
- クライアントデータのキャッシュと最適化
- クライアント側でのさまざまなデータロジック処理、およびページの変更に対応
さらに恐ろしいのは、シングルページアプリケーションの人気により、フロントエンド開発者は、データが可能な限り独立し、相互に影響を与えないようにしながら、さまざまな状況に応じて1つのページに異なるページ構造を組み立てる必要があることです。間違いなくそれは巨大なプロジェクトです。
シングルページアプリケーション:Webサイト全体には1ページしかなく、ブラウジングプロセス全体でユーザーが操作しても、ページは更新されません。ユーザーがローカルプログラムを使用しているかのように、シングルページアプリケーションのユーザーエクスペリエンスは非常に優れています。
上記の状況は直接結果につながります。つまり、JSコードの数が急激に増加しましたが、これは過去に比べて桁違いではありません。
ただし、JSコードの量が急増しているため、フロントエンド開発に前例のないプレッシャーがかかっています。ブラウザ側では、ノード環境のようなモジュラー開発機能がないため、必然的に次の問題が発生します。
- コードを分離する方法は?
- コード分離後、ブラウザーがjsを参照する場合、それらの間の依存関係をどのように処理しますか?
- コードを分離した後、ブラウザがjsを参照すると、追加のリクエストが発生します。効率の問題を解決するにはどうすればよいですか?
これらの問題を解決して初めて、クライアント側でリッチで柔軟性があり、堅牢なコード構造を作成できます。
サードパーティのモジュラー仕様
私たちが最初に遭遇した最初の問題は、コードの分離とブラウザー側の依存関係の問題をどのように解決するかでした。
CommonJS
CommonJSは優れた仕様ですが、ブラウザー側で実装する場合は、いくつかの問題が発生します。
といった:
var math = require('math'); //导入math模块math.add(2,3); // 5
このコードがノード環境にある場合は問題ありません。ノード環境ではファイルを読み取ることができ、require()
関数がファイルを読み取り、モジュールのjsコードを取得して実行するためです。
ただし、ブラウザー環境では、ファイルを読み取る方法はありません。ブラウザーで、本当にCommonJS仕様を実装する場合は、require()
関数にネットワーク要求を送信させてjsコードを取得する必要があります。このプロセスは非常に時間がかかり、その時代には非同期(Promise)がなかったため、CommonJS仕様をブラウザー側で実装することは困難でした。
AMD仕様
CommonJSは主にバックエンド(ノード環境)でのJSのパフォーマンスのために策定されていますこれはフロントエンドには適していませんAMD(非同期モジュール定義)が登場し、主にフロントのパフォーマンスの仕様を策定します-JSを終了します。
AMDは「非同期モジュール定義」の略語で、「非同期モジュール定義」を意味します。モジュールを非同期でロードし、モジュールのロードはそれに続くステートメントの実行に影響を与えません。このモジュールに依存するすべてのステートメントは、コールバック関数で定義されます。コールバック関数は、ロードが完了するまで実行されません。
AMDもrequire()ステートメントを使用してモジュールをロードしますが、CommonJSとは異なり、次の2つのパラメーターが必要です。
require([module], callback);
最初のパラメーター[module]は配列であり、そのメンバーはロードされるモジュールです。2番目のパラメーターcallbackは、ロードが成功した後のコールバック関数です。前のコードをAMD形式に書き換えると、次のようになります。
require(['math'], function (math) {
math.add(2, 3);
});
math.add()は、数学モジュールの読み込みと同期されておらず、ブラウザーは中断されません。したがって、明らかに、AMDはブラウザ環境により適しています。現在、AMD仕様を実装するJavascriptライブラリは主にrequire.jsとcurl.jsの2つです。
requirejsチュートリアル:http: //www.requirejs.cn/
CMD仕様
フロントエンドのビッグNiuYubo (http://caibaojian.com/)はseajsを作成しました。これは、AMDと非常によく似たCMD仕様に準拠していますが、使い勝手が良いと感じています。最も重要なのは中国語版です。 (http://seajs.org/docs/#docs)
seajsは次のようになります。
define(function(require,exports,module){ //...});
CMDとAMDの違い:
- ポジショニングに違いがあります。RequireJSは、ブラウザー側のモジュールローダーであると同時に、Rhino / Nodeなどの環境のモジュールローダーでもありたいと考えています。Sea.jsはWebブラウザー側に重点を置いていると同時に、ノード拡張機能を介してノード環境で簡単に実行できます。
- さまざまな仕様に従います。RequireJSはAMD(非同期モジュール定義)仕様に従い、Sea.jsはCMD(共通モジュール定義)仕様に従います。仕様の違いにより、2つの間のAPIが異なります。Sea.jsは、CommonJS Modules /1.1およびNodeModulesの仕様に近いものです。
- プロモーションの概念には違いがあります。RequireJSは、サードパーティのライブラリがRequireJSをサポートするように自身を変更できるようにしようとしていますが、現在、それを採用しているコミュニティはごくわずかです。Sea.jsはそれを強制的にプッシュせず、「すべての川をカバーする」ために独立したパッケージングを採用しています。現在、比較的成熟したパッケージング戦略があります。
- 開発とデバッグのサポートは異なります。Sea.jsはコードの開発とデバッグに細心の注意を払っており、nocacheやdebugなどのデバッグ用のプラグインがあります。RequireJSはこれを明確にサポートしていません。
- プラグインのメカニズムは異なります。RequireJSは、ソースコードでインターフェイスを予約する形式を取り、プラグインタイプは比較的単一です。Sea.jsは、より豊富なタイプのプラグインを備えた一般的なイベントメカニズムを採用しています。
総括する
CommonJS、AMD、CMDのいずれであっても、これらはすべてモジュラー開発を実現するための仕様です。
その中で、CommonJSはノード環境で最も一般的な仕様ですが、AMDとCMDは主にクライアントのモジュール化に重点を置いています。
しかし、これらすべては徐々に歴史になりつつあります。ECMAScript6が誕生した後、モジュラー仕様はついに公式の標準を持ちました。
ES6のモジュール性
ES6では、標準のモジュラープログラミング仕様が提案されました。現在、ES6をサポートするほとんどのブラウザはすでにこの仕様をサポートしています。
その一般的なルールは次のとおりです。
- JSファイル、つまりモジュール
- モジュール内のすべてのデータは、エクスポートされない限り、プライベートデータであり、モジュール内でのみアクセスできます
- exportキーワードを使用してモジュールをエクスポートします
- importキーワードを使用してモジュールをインポートし、非構造化式を使用してインポート時にエクスポートされたデータを取得します。それ以外の場合は、エクスポートされたデフォルトデータが使用されます。
- モジュールは複数のエクスポートを持つことができます
- インポートされたモジュールはキャッシュされます
- 使用するページにエントリモジュールをロードします
<script type="module" src="入口模块">
残念ながら、ノードのネイティブ環境は当面ES6のモジュラー仕様をサポートしていませんが、当局は将来それをサポートすることを約束しました。
モジュールのエクスポート
exportキーワードを使用して、公開されたコードの一部を他のモジュールに公開できます。最も簡単な方法は、次のよう
に、変数、関数、またはクラス宣言の前にエクスポートを配置し、モジュールからそれらを公開することです。
//mymodule.js// 导出数据export var color = "red";
export let name = "Nicholas";
export const magicNumber = 7;// 导出函数export function sum(num1, num2) { return num1 + num2;
}// 导出类export class Rectangle {
constructor(length, width) { this.length = length; this.width = width;
}
}// 此函数为模块私有function subtract(num1, num2) { return num1 - num2;
}// 定义一个函数……function multiply(num1, num2) { return num1 * num2;
}// ……稍后将其导出export {
multiply
};
上記のコード、最終的なエクスポートコンテンツは次のとおりです。
{
color: "red",
name: "Nicholas",
magicNumber: 7,
sum: function,
Rectangle: class,
multiply: function
}
export
キーは宣言ステートメントの前に配置する必要がありますが、変数を直接エクスポートしない ことは注目に値し ます。たとえば、export multiply
既存の変数をエクスポートする場合は、オブジェクトリテラルと一緒にパッケージ化する必要があります。export {multiply}
モジュールのインポート
エクスポートを含むモジュールを作成したら、他のモジュールでimportキーワードを使用して、エクスポートされた関数にアクセスできます
。importステートメントには2つの部分があり、1つはインポートする必要のある識別子であり、もう1つはインポートする必要のある識別子のソースモジュールです。
importステートメントの基本的な形式は次のとおりです。
//usemodule.jsimport { color, name, multiply } from "./mymodule.js";
このようにして、データの一部が前のモジュールからインポートされます。
次の方法で、モジュール内のすべてをインポートすることもできます。
//usemodule.jsimport * as all from "./mymodule.js"; // all可以是任意的名称//导入后,all是一个对象,包含模块中导出的所有内容
エクスポートとインポートの両方に重要な制限があります。つまり、他のステートメントまたは式の外部で使用する必要があります。たとえば、次のコードには構文エラーがあります
。if(flag){export flag; //構文エラー} function tryImport(){import flag from "./example.js";//構文エラー}
デフォルト値のインポートとエクスポート
ES6では、インポートとエクスポートの構文を簡素化するために、インポートとエクスポートの方法(デフォルト値)も提供されます。この方法でインポートとエクスポートが簡単になりますが、各モジュールはエクスポートしかできないことに注意してください。1つのデフォルト値。
デフォルト値のエクスポート:
export default function(num1, num2) { return num1 + num2;
}
上記のコードは、CommonJSのmodule.exportsに似ています。
//example.jsmodule.exports = function(num1, num2) { return num1 + num2;
}
デフォルトのエクスポートを使用する場合、変数を直接エクスポートできます。
var color = "red";
export color; //错误,普通的导出语句,必须放到声明语句前,或对象字面量前export default color; //正确,默认导出可以使用这种方式
デフォルト値のインポート:
次の構文を使用して、モジュールからデフォルト値をインポートできます。
import sum from "./example.js";
このインポートステートメントは、example.jsモジュールからデフォルト値をインポートします。ここでは中括弧は使用されていないことに注意してください。
これは、デフォルト以外のインポートで以前に見たものとは異なります。ローカル名の合計は、デフォルトでターゲットモジュールによってエクスポートされる関数を表すために使用されます。この構文
は最も簡潔であり、ES6標準メーカーは、
既存のオブジェクトをインポートできるように、これがインターネットでのインポートの主要な形式になることも期待しています。
デフォルト値と1つ以上のデフォルト以外のバインディングの両方をエクスポートするモジュールの場合、単一のステートメントを使用して、
そのすべてのエクスポートバインディングをインポートできます。たとえば、次のようなモジュールがあるとします。
//example.jsexport let color = "red";
export default function(num1, num2) { return num1 + num2;
}
次のようにimportステートメントを使用して、色と関数をデフォルト値として同時にインポートできます。
import sum, { color } from "./example.js";console.log(sum(1, 2)); // 3console.log(color); // "red"
ブラウザでエントリモジュールを使用する
nodejsでは、node app.js
起動のために特定のモジュールを実行するために使用できます。ブラウザで操作するにはどうすればよいですか?