Javascript のモジュール性の詳細な紹介

不言
リリース: 2018-09-05 11:55:34
オリジナル
1622 人が閲覧しました

この記事は Javascript のモジュール化について詳しく説明しています。必要な方は参考にしていただければ幸いです。

まえがき

Web テクノロジーの精力的な発展と、それが依存するインフラストラクチャがますます完璧になるにつれて、フロントエンドの分野はブラウザーからサーバー (Node.js)、デスクトップ (PC、Android、iOS)、 JavaScript がこれらのアプリケーションの中核部分を担うモノのインターネット (IoT) でさえ、その規模と複雑さが指数関数的に増大するにつれて、ソフトウェア エンジニアリング システム (共同開発、単体テスト、要件と欠陥管理など) も確立されています。 )、モジュール式プログラミングの需要がますます高まっています。

JavaScript によるモジュール型プログラミングのサポートはまだ標準化されておらず、この重要な任務を担うのは困難ですが、一時は戦士たちが前進してすべての障害を克服し、焼き畑農業から未来志向のモジュール型ソリューションに移行しました。

コンセプト

モジュラープログラミングは、いくつかの __比較的独立した再利用可能なモジュール__ を組み合わせることによって機能を実現することです。モジュールの場合、各モジュール内の実行ロジックは外部からは認識されず、一部のメソッドとデータのみをエクスポート (公開) します

  • モジュールが導入されると、同期/非同期でロードされ、導入されるコードが実行されます。そして、その公開されたメソッドとデータが取得されます

  • 焼き畑農業

  • JavaScript 言語レベルではモジュール型ソリューションが提供されませんが、__オブジェクト指向__言語機能を使用すると、__デザイン パターン__のサポートにより、いくつかの簡単なソリューションが提供されます。モジュール型アーキテクチャは実現できます。典型的なケースは、モジュール性を実現するためにシングルトン パターンを使用することです。これにより、モジュールをより適切にカプセル化し、それを使用する必要がある人にのみ情報を公開できます。即時実行関数 (IIFE) を使用して依存関係を宣言し、データをエクスポートすることは、現在のモジュラー ソリューションと大きな違いはありませんが、本質的に異なり、モジュールを定義するときに満たせない重要な問題がいくつかあります。宣言された依存関係は自動的に導入されることは強制されません。つまり、モジュールを定義する前に依存モジュールのコードを手動で導入する必要があります。

モジュールが定義されるとき、そのコードはすでに実行プロセスを完了しており、オンデマンドでロードすることはできません。 ;

    ファイル間でモジュールを使用する場合、モジュールはグローバル変数 (ウィンドウ) にマウントする必要があります
  • AMD と CMD は 2 つの部分に分かれています
  • 余談: これら 2 つのモジュラー ソリューションは古いため、歴史の舞台から徐々に消え去り、特定の機能については詳細に議論されなくなりました

    「焼き畑」時代の残りのニーズを解決するために、AMD および CMD のモジュラー仕様が登場しました。ブラウザ側での非同期モジュラー プログラミングの必要性を解決しました。 __other 基本原則は、スクリプトとイベント リスニングを動的にロードすることでモジュールを非同期にロードすることです。 __

  • AMD と CMD の 2 つの最も代表的な作品は、require.js と sea.js に対応します。それぞれ、主な違いは依存関係の宣言と依存関係にあります。require.js はデフォルトで宣言されたときに実行されますが、sea.js は遅延ロードとオンデマンドの使用を推奨しています。また、CMD の記述方法にも言及する価値があります。仕様は CommonJS に非常に似ており、わずかな変更を加えるだけで CommonJS で使用できます。次のケースを参照すると理解しやすくなります。2009 年に、CommonJS はコア機能の 1 つとしてサーバー側のシナリオに適しています。検査と時間の経過、およびフロントエンド エンジニアリングの完全なサポートを経て、CommonJS は Node.js とブラウザーで広く使用されています。 : モジュールのエクスポートされた部分、つまり公開されたコンテンツ
  • require (関数): モジュールをロードし、ターゲットモジュールのエクスポートされた値を取得する関数 (基本型はコピー、参照型は浅いコピー) )、組み込みモジュール、npm モジュール、カスタム モジュールをロードできます

実装

1. モジュール定義

デフォルトでは、すべての .node .js .json ファイルは仕様に準拠するモジュールです

。 2. モジュールをインポートします

まずキャッシュ (require.cache ) からモジュールを読み取り、キャッシュが見つからない場合はパス分析が実行され、さまざまなタイプのモジュールに従って処理されます:

  • 組み込みモジュール、メモリから直接ロードされます。

  • 外部モジュールは、最初にファイルのアドレス指定と配置を実行し、次にコンパイルして実行し、最後に対応するエクスポート値を取得します

  • コンパイルプロセス中に、Node は取得した JavaScript のコンテンツをラップします。ファイルの先頭と末尾は次のとおりです:

    // Define a module
    var moduleA = (function ($, doc) {
      var methodA = function() {};
      var dataA = {};
      return {
        methodA: methodA,
        dataA: dataA
      };
    })(jQuery, document);
    
    // Use a module
    var result = moduleA.mehodA();
    ログイン後にコピー
  • 機能の概要

同期モジュール宣言とインポートロジックを実行し、一部の複雑な依存関係参照(循環依存関係など)を分析する場合は注意してください。パフォーマンスが向上し、メモリ使用量が制限されます。

モジュールは柔軟に変更できます。高い精度で、一部のカスタマイズ要件を実現できます (ホット アップデート、あらゆるファイル タイプのモジュール サポートなど)。

ES Module(推荐使用)

ES Module 是语言层面的模块化方案,由 ES 2015 提出,其规范与 CommonJS 比之 ,导出的值都可以看成是一个具备多个属性或者方法的对象,可以实现互相兼容;但写法上 ES Module 更简洁,与 Python 接近;

import fs from 'fs';
import color from 'color';
import service, { getArticles } from '../service'; 

export default service;
export const getArticles = getArticles;
ログイン後にコピー

主要差异在于:

  • ES Module 会对静态代码分析,即在代码编译时进行模块的加载,在运行时之前就已经确定了依赖关系(可解决循环引用的问题);

  • ES Module 关键字:import export 以及独有的 default  关键字,确定默认的导出值;

  • ES Module 中导入模块的属性或者方法是强绑定的,包括基础类型;

UMD

通过一层自执行函数来兼容各种模块化规范的写法,兼容 AMD / CMD / CommonJS 等模块化规范,贴上代码胜过千言万语,需要特别注意的是 ES Module 由于会对静态代码进行分析,故这种运行时的方案无法使用,此时通过 CommonJS 进行兼容;

(function (global, factory) {
  if (typeof exports === 'object') {   
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    define(factory);
  } else {
    this.eventUtil = factory();
  }
})(this, function (exports) {
  // Define Module
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = 42;
});
ログイン後にコピー

构建工具中的实现

为了在浏览器环境中运行模块化的代码,需要借助一些模块化打包的工具进行打包( 以 webpack 为例),定义了项目入口之后,会先快速地进行依赖的分析,然后将所有依赖的模块转换成浏览器兼容的对应模块化规范的实现;

模块化的基础

从上面的介绍中,我们已经对其规范和实现有了一定的了解;在浏览器中,要实现 CommonJS 规范,只需要实现 module / exports / require / global 这几个属性,由于浏览器中是无法访问文件系统的,因此 require 过程中的文件定位需要改造为加载对应的 JS 片段(webpack 采用的方式为通过函数传参实现依赖的引入)。具体实现可以参考:tiny-browser-require。

webpack 打包出来的代码快照如下,注意看注释中的时序;

(function (modules) {
  // The module cache
  var installedModules = {};
  // The require function
  function __webpack_require__(moduleId) {}
  return __webpack_require__(0); // ---> 0
})
({
  0: function (module, exports, __webpack_require__) {
    // Define module A
    var moduleB = __webpack_require__(1); // ---> 1
  },
  1: function (module, exports, __webpack_require__) {
    // Define module B
    exports = {}; // ---> 2
  }
});
ログイン後にコピー

实际上,ES Module 的处理同 CommonJS 相差无几,只是在定义模块和引入模块时会去处理 __esModule 标识,从而兼容其在语法上的差异。

异步和扩展

1、浏览器环境下,网络资源受到较大的限制,因此打包出来的文件如果体积巨大,对页面性能的损耗极大,因此需要对构建的目标文件进行拆分,同时模块也需要支持动态加载;

webpack 提供了两个方法 require.ensure() 和 import() (推荐使用)进行模块的动态加载,至于其中的原理,跟上面提及的 AMD & CMD 所见略同,import() 执行后返回一个 Promise 对象,其中所做的工作无非也是动态新增 script 标签,然后通过 onload / onerror 事件进一步处理。

2、由于 require 函数是完全自定义的,我们可以在模块化中实现更多的特性,比如通过修改 require.resolve 或 Module._extensions 扩展支持的文件类型,使得 css / .jsx / .vue / 图片等文件也能为模块化所使用;

附录:特性一览表

模块化规范 加载方式 加载时机 运行环境 备注
AMD 异步 运行时 浏览器
CMD 异步 运行时 浏览器
CommonJS 同步/异步 运行时 浏览器 / Node
ES Module 同步/异步 编译阶段 浏览器 / Node 通过 import() 实现异步加载

相关推荐:

javascript模块化编程(转载),javascript模块化

JavaScript模块化思想

以上がJavascript のモジュール性の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート