3

次の Javascript 初期化ステートメントの解読に問題があります。

(function(NAMESPACE) {
        NAMESPACE.nav = {};
        var nav = NAMESPACE.nav,

_init = false,
        _isNavOpen = false,
        _inner = document.getElementById('inner-wrap');

    // constants
    nav.CLASS = 'js-nav-open';
    nav.CLASS_READY = 'js-nav';
    nav.CONTAINER = '#nav';
    nav.DURATION = 400;
    nav.HAS_CSSTRANSITIONS = $('html').hasClass('csstransitions') && $('html').hasClass('csstransforms3d');

... ... ...

// toggle open/close
    nav.toggle = function(event) {
        event.stopPropagation();

        if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
            nav.close();
        } else {
            nav.open();
        }

        // this is for the links
        if(event) {
            event.preventDefault();
        }
    };

}(PROJECT_NAME));

不必要に複雑に思えます - 'nav' を 2 行で 3 回呼び出します (または設定しますか?)。誰かがこのようにひっくり返すことのポイントを説明できますか?

4

3 に答える 3

4

これは、jQuery を使用する場合の一般的な方法です。

(function ($) {
    var div = $('#my-div');
    // Etc
}(jQuery));

スクリプトをクロージャでラップする、特定の変数が期待どおりの値を持つようになります。

たとえば、jQuery は$ほぼすべてのことを行うために を使用します。ほとんどの人$('do something')jQuery('do something').

しかし、グローバル変数を使用する別のライブラリがページにあるとします$

コードをクロージャでラップすることにより、jQuery として "予約" し$、jQuery だけを使用できます。jQuery(クロージャに引数として渡す場合、この関数のスコープ内で$は「jQuery」のみを意味します。)


同様に、あなたの例では、NAMESPACE変数を予約しています。と呼ばれる別の変数があったとしてもNAMESPACE、クロージャーの最後に変数を渡すことで、ページのどこか別の場所でラケットを引き起こし、それNAMESPACEが期待するオブジェクトになることが保証されます (少なくともクロージャー内で)。 .

というグローバル変数がありましたが、ショートカットとしてAbominableSnowman使用したいとします。ASこれを行うことにより:

var AS = "Apple Soup";

(function (AS) {
    AS.tellMeAboutSnowmen();
    alert(AS.snowballs);
}(AbominableSnowman));

コードは意図したとおりに機能します。(証明: http://jsfiddle.net/RUzZH/1/ )


「ひっくり返す」に関しては、元のプログラマーが短縮NAMESPACE.navしたかったようnavです。これはおそらくそれを行うための最良の方法でした。

別の方法 (非推奨):

// It's best to limit your assignments to 1-per-line
// This kind of code isn't fun to debug, or even read
var nav = NAMESPACE.nav = {};

悩むほどのことではないようです。ただし、このスクリプトはNAMESPACE.nav頻繁に と対話するため、変数を使用して.navプロパティを直接参照する方が少し、少し速くなります。nav(これは実際にはマイクロ最適化ですが、この場合は別の理由で [わかりやすくするために]都合よく正当化できます。)

于 2013-10-01T01:09:03.490 に答える
4

これは、プライベート スコープを作成し、オブジェクトがグローバル スコープを汚染しないようにするために一般的に使用される JavaScript クロージャの例です。

この方法でプラグインを作成して、同じ名前の変数などの結果としてページ上の他の機能との競合を回避することは非常に一般的です。本質的に、これはスコープを管理するためのメカニズムです。

于 2013-10-01T00:51:45.670 に答える
3

行ごとの説明は次のとおりです(分割するためだけにヘッダーを付けています):

セットアップ:

// Create an anonymous function expression taking `NAMESPACE` as a parameter.
// Likely the *real* namespace will be passed to the function at the end
// with ... })(realnamespacetomodify);
(function(NAMESPACE) {

// Create the new part of the namespace.  Note that we are editing a reference
// so really this change happens on whatever object was passed in.
    NAMESPACE.nav = {};

// Create a local pointing to this new sub-namespace.  Probably just for
// convenience, also possibly for portability (if the name is used in closures,
// then those closures don't need to refer to NAMESPACE directly).
    var nav = NAMESPACE.nav,

モジュール定義:

// While nav refers to an object likely in global scope, nav itself can
// never be referred to from global scope because it is a local here.

// These variables are local here.  They can never be referred to by global scope.
    _isNavOpen = false,
    _inner = document.getElementById('inner-wrap');

// These variables, added to nav, can be accessed using the object that
// nav refers to in global scope (see the end).
    nav.CLASS = 'js-nav-open';
    ... 

// This function is also added to nav, therefore it can be accessed outside
    nav.toggle = function(event) {
        ...

        // This reference to _isNavOpen resolves because this function
        // is a closure, and binds variables outside its scope
        // to the function itself.  So even though _isNavOpen can't be
        // accessed globally, it can be accessed here, making it like
        // a private member of this namespace.
        if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
            // nav is also bound by the closure and can be accessed here
            nav.close();
        } ...
    };

グローバル空間で使用:

}(PROJECT_NAME));

console.log(PROJECT_NAME.nav.CLASS); // "js-nav-open"
console.log(PROJECT_NAME.nav.toggle); // Function object

モジュールパターンです。いくつかの理由で使用されます。

  • コードの移植性(モジュール内のグローバル オブジェクトを参照しない)
  • スコーピング(不要な変数をグローバル名前空間に割り当てないようにする)
  • 可視性(プライベート アクセス変数の非表示)

最初の 3 行自体 (元の質問)については、直接参照できますが、コードの移植性PROJECT_NAMEを支援するために設定されているようです。無名関数自体が実際のオブジェクト ( ) を決して指していないことに気付くでしょう。つまり、この部分をコピーして貼り付け、その参照を 1 か所だけ変更できます。PROJECT_NAME

他の回答ではスコープについて言及していますが、これも重要ですが、既存のグローバル変数を直接参照しない理由など、このコードのすべての利点を説明しているわけではありません。スコープを隠す利点自体は、パターンのこの部分で実現されます。

(function() {
  ... // Anything set here is local, not global.

})();
于 2013-10-01T00:59:37.113 に答える