ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptモジュールプログラミングの詳細な説明

JavaScriptモジュールプログラミングの詳細な説明

PHPz
PHPzオリジナル
2017-04-04 14:00:331467ブラウズ

1. IIFE の説明

は、即時に呼び出される関数式、つまり即時に実行される関数 について説明します。

次のコードに示すように、これは匿名の即時実行関数です:

(function(window, undefined){
  // 代码...    
})(window);

2. 括弧の意味

2.1 function(){}function(){}的括号的意义

 这个括号的目的,是为了把function(){}转化为表达式。像一些库的源码,喜欢用如下方式代替:

~function(){
  // 代码...
}();

或者这种方式:

+function(){
  // 代码...
}();

 其实,作用都一样,都是把function(){}转化成一个可执行的表达式,方便执行。
 如果去掉该括号,则会报错。因为单纯的function(){}不是可执行的表达式,会直接报错。如下图:

JavaScriptモジュールプログラミングの詳細な説明


2.1 第二个括号的意义

 理解了第一个括号的意义,第二个括号就很简单了,就是执行表达式了。

三、参数的意义

 以这段代码为例子,讲解参数

var wall = {};
(function(window, WALL, undefined){

})(window, wall);

 参数分为形参和实参。
function(window, WALL, undefined)三个参数为形参,第二个括号(window, wall)的两个参数为实参。
 也即可以理解为 window == windowwall == WALL

2.1 普通形参

 普通形参是指由windowwall这样的实际变量传入指定,可以为任何类型的变量。一个形参就对应一个实参

2.2 特殊形参undefined

 为什么形参要多写一个undefined,这是一个很有趣的话题。
 可以知道这个示例,实参只有两个,而形参有三个。所以在函数执行的时候,形参undefined会默认赋值为undefined。

 形参undefined的作用如下:

2.2.1 防止特殊值undefined被恶意代码篡改。
 IE6等低版本浏览器,undefined是支持被修改的。而这个特殊值被修改后,像以下这种判断就失效了。

if(wall == undefined){
  // 代码...
}

 所以,这里多加一个形参的目的就是为了防止这种情况发生。只要在这个IIFE作用域内,undefined就能够正常获取到。

2.2.2 压缩代码可以压缩undefined
 因为undefined作为形参,像YUI compressor这种类型的代码压缩工具,可以将其相关的值进行压缩,减小文件的体积。

四、写法解析

4.1 普通写法

var wall = {}; // 声明定义一个命名空间wall

// 定义方法
(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    };
})(window, wall);

(function(window, WALL, undefined){
    // 给wall命名空间绑定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    };
})(window, wall);

// 调用
wall.say();
wall.whoIam();

 先定义一个命名空间,然后再给这个命名空间加东西。这是最普遍的写法,也是最好理解的。
 不足的地方就是必须先声明一个命名空间,然后才能执行相关的绑定代码。存在顺序加载的问题。

4.2 放大模式

var wall = (function(window, WALL, undefined){
    if(typeof WALL == 'undefined'){
        WALL = {};
    }

    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }

    return WALL; // 返回引用
})(window, wall);

var wall = (function(window, WALL, undefined){
    if(typeof WALL == 'undefined'){
        WALL = {};
    }

    // 给wall命名空间绑定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    }

    return WALL; // 返回引用
})(window, wall);

// 调用
wall.say();
wall.whoIam();

 放大模式的好处就是,可以不用考虑代码加载的先后顺序。
 因为js允许wall变量进行重复var声明,所以这段代码是可以执行的。
 我可以把IIFE函数拆分成多个文件进行加载,而不会出现普通写法需要注意的问题。

需要注意的点
 1.IIFE的头部,都要先进行检查命名空间是否已经实例化,如果还没实例化,则进行实例化。
 2.IIFE的尾部,都要return命名空间的引用,使后续代码能够得到最新的wall命名空间内容。

4.3 宽放大模式

(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

(function(window, WALL, undefined){
    // 给wall命名空间绑定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    }
})(window, window.wall || (window.wall = {}));

// 调用
wall.say();
wall.whoIam();

宽放大模式的重点注意的地方:就是在实参部分的window.wall || (window.wall = {})
 用||运算符进行取巧。
 如果window.wall是已经实例化的,非not defined。则直接返回window.wall的引用,赋值给形参WALL。不会执行||运算符后面的内容。
 如果window.wall还未实例化,则进行实例化。这里要注意的点是实例化是一个赋值操作,需要用括号包起来,变成表达式去执行,才不会报错。
 表达式(window.wall = {})执行完毕后,会返回新对象window.wall

この括弧の目的は、function(){} を式に変換することです。一部のライブラリのソース コードと同様に、私は代わりに次のメソッドを使用することを好みます: 🎜
;(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));
🎜 またはこのメソッド: 🎜
// a.js 文件
wall.log()

// b.js 文件
(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));
🎜 実際、効果は同じで、function(){} を変換します。 code> を実行可能な式に変換して簡単に実行できるようにします。 <br> 括弧が削除されると、エラーが報告されます。単純な <code>function(){} は実行可能な式ではなく、直接エラーを報告するためです。以下に示すように: 🎜

JavaScriptモジュールプログラミングの詳細な説明
🎜


🎜🎜 🎜2.1 2 番目の括弧の意味🎜🎜 1 番目の括弧の意味が理解できれば、2 番目の括弧は非常に簡単です。式を実行するだけです。 🎜🎜3. パラメータの意味🎜🎜 このコードを例にしてパラメータを説明します 🎜rrreee🎜 パラメータは仮パラメータと実パラメータに分けられます。
function(window, WALL, unknown) の 3 つのパラメータは仮パラメータ、2 番目の括弧 (window, Wall) の 2 つのパラメータは実パラメータです。 。
window == windowwall == WALL とも解釈できます。 🎜🎜 🎜2.1 通常の仮パラメータ🎜🎜 通常の仮パラメータとは、実際の変数🎜を指します。渡され、任意のタイプの変数を指定できます。 1 つの仮引数は 1 つの実引数に対応します🎜🎜 🎜2.2 特別な仮引数 未定義🎜🎜 なぜ仮引数に余分な未定義を記述する必要があるのでしょうか これは非常に興味深いトピックです。
この例でわかるように、実際のパラメータは 2 つと仮パラメータは 3 つだけです。したがって、関数が実行されると、仮パラメータ unknown には、デフォルトで値 unknown が割り当てられます。 🎜🎜 仮引数 unknown の機能は以下のとおりです。 🎜🎜 🎜2.2.1 特殊な値 unknown が悪意のあるコードによって改ざんされることを防ぎます。
IE6 などの下位バージョンのブラウザでは、未定義を変更できます。この特別な値を変更すると、以下のような判定が無効になります。 🎜rrreee🎜 したがって、ここで追加の形式パラメータを追加する目的は、この状況が発生するのを防ぐことです。この IIFE の範囲内であれば、unknown も正常に取得できます。 🎜🎜 🎜2.2.2 圧縮コードは未定義を圧縮できる
未定義は仮パラメータとして使用されるため、YUI compressor のようなコード圧縮ツールは関連する値を圧縮し、ファイル サイズを削減できます。 🎜🎜4. 記述分析🎜🎜 🎜4.1 一般的な記述方法🎜rrreee🎜 まず名前空間を定義し、この名前空間に物を追加します。これは最も一般的な書き方であり、最も理解しやすいです。
欠点は、関連するバインディング コードを実行する前に、最初に名前空間を宣言する必要があることです。順次ロードに問題があります。 🎜🎜 🎜4.2 増幅モード🎜rrreee🎜 増幅モードの利点は、コードがロードされる順序を考慮する必要がないことです。
js🎜 では、wall 変数の var 宣言を繰り返すことができるため、このコードは実行可能です。
IIFE 関数を複数のファイルに分割して読み込むことができ、通常の記述で注意する必要のある問題は発生しません。 🎜🎜 🎜 注意点:
1. IIFE のヘッダーは、まず名前空間がインスタンス化されているかどうかを確認する必要があります。インスタンス化されていない場合は、インスタンス化します。
2. IIFE の最後に、後続のコードが最新の wall 名前空間コンテンツを取得できるように、名前空間への参照を返す必要があります。 🎜🎜 🎜4.3 ワイド拡大モード🎜rrreee🎜 🎜 ワイド拡大モードで注意すべきポイント:window.wall || (window.wall = {}) です。実際のパラメータセクションにあります。
トリックには ||
演算子 🎜 を使用します。
window.wall がインスタンス化されている場合、それは定義されていません。次に、window.wall の参照を直接返し、それを仮パラメータ WALL に割り当てます。 || 演算子に続く内容は実行されません。
window.wall がまだインスタンス化されていない場合は、インスタンス化します。ここで注意すべき点は、インスタンス化は代入操作であり、エラーが報告されないように、実行するには括弧で囲んで式に変換する必要があるということです。
(window.wall = {}) が実行されると、新しい
オブジェクト 🎜window.wall の参照が返されます。 🎜

宽放大模式的好处:是可以切割成多个文件进行加载,而不必考虑文件加载的先后顺序,不存在强耦合关系。
 当然,如果IIFE里面的方法互相引用,还是存在加载依赖的问题。这个问题可以用加载器
Require.js等工具解决,这里就不讨论了。

五、分文件加载IIFE要注意的点

;(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

 眼尖的已经看出区别了,就是文件开始的地方,先写上分号;
 这样,多个文件合并的时候,才不会出现收尾相接,代码出现错乱的问题。比如下面这种情况:

// a.js 文件
wall.log()

// b.js 文件
(function(window, WALL, undefined){
    // 给wall命名空间绑定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

 由于a.js文件的wall.log()少写了分号,跟b.js文件合并后,js就会认为‘wall.log()(...)’是需要这么执行的,结果代码就报错了。


 觉得不错的,可以关注<a href="http://www.php.cn/js/js-weixinapp-module.html" target="_blank">模块化</a>这个系列的文章,容我后续码字,敬请期待!


以上がJavaScriptモジュールプログラミングの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。