クローズ心が世界の包括的である、あなたは一人で、クロージャではありません

出発点

この記事ありふれた記事を書いた理由は、次のデザインパターンへの道を開くことです。今すぐペンを持っているあなたは、それを変更しないことを意図していることを、書き込みを続け、私は多くの人々が存在しなければならないと信じてやや曖昧な概念を閉鎖、その後、周りを見て、見て
、すべての閉鎖後と高次機能の両方開発のコンセプトは、非常に重いです。メリット、美しさの多くは、その後、私たちは、今日のテーマは、閉鎖&高階関数を起動し、ブッシュについてビートはありません

クロージャ

クロージャは正面から切っても切れないトピックえー、だけでなく、概念を理解するために理解する必要があり、困難です。クロージャといえば、それは変数と変数のスコープのライフサイクルに密接に関連しています。
両方の知識は、我々はバイパス、そして、理解できないあなたとしている
変数のスコープ
二つのカテゴリーに最初の変数のスコープ:グローバルスコープとローカルスコープ、これは皆を感動理解。私たちはしばしば、実際には変数の主なスコープは関数スコープ内で宣言されていることを言います

あなたはグローバル変数に代わって、関数の変数を宣言しませvarキーワード
varキーワードで宣言された関数では、その変数はローカル変数は、ローカル変数は関数内でのみアクセスすることができません

function fn() {
    var a = 110;     // a为局部变量
    console.log(a);  // 110
}
fn();
console.log(a);     // a is not defined  外部访问不到内部的变量

上記のコードでは、関数の外に取得していない関数内のローカル変数の宣言を示しています。ちょっと傲慢な低出生体重児は、コーダの難しさのために、それはの手紙に劣らかかりません
、Keguan、門司を風の歌を聴け。あなたはまだJSを覚えていますか、機能が、「ファーストクラスの市民、」ああ、大幅に悪化低下
あなたは可変時間を探している場合、この変数の機能には文が存在しない場合、この関数は、関数のスコープ、関数スコープを作成することができ、外側の関数に見ていきます、グローバル変数は、これまでに発見されている
、いわゆるスコープチェーンを形成しており、変数が内側から外を見るように、

var a = 7;
function outer() {
    var b = 9;
    function inner() {
        var c = 8;
        alert(b);
        alert(a);
    }
    inner();
    alert(c);   // c is not defined
}
outer();    // 调用函数

スコープチェーンの使用、我々が取得しようと、FN機能の変換

function fn() {
    var a = 110;     // a为局部变量
    return function() {
        console.log(a);
    }
    console.log(a);  // 110
}
var fn2 = fn();
fn2();      // 110

このようなと、このようなやな、そう、簡単で、小さなケースの事、あなたは外部からローカル変数にアクセスすることができ
、これまで、我々はその閉鎖で意味を発見した:閉鎖は、他の内部機能を読み取る能力であります関数、変数、ああ、何の問題は、読み

変数のライフサイクル

上記の低出生体重児を取得する方法の問題を解決するには、その後、我々として可変のライフサイクルの概念を簡単に超える行くかもしれません。

グローバル変数の場合は、その自然のライフサイクルは永久的である(永遠に)、我々は満足していない場合を除き、それを取り除くためのイニシアチブを取る、それが払い戻さ。
関数内のローカル変数のとしての機能が終了すると、ローカル変数に値を失っている、それはのようにごみ出しにガベージコレクションだったので、ラッキー、varで宣言されていない
次のようなこのコード非常に貧しいです

function fn() {
    var a = 123;    // fn执行完毕后,变量a就将被销毁了
    console.log(a);
}
fn();

上記のガベージコレクションプロセスは、我々は、ああ悲しい涙を聞いたことがあるが、リスナーを見たことはできませんが。そう残酷なことはできません、私はあなたサンセイIIIのために、すべてを与えるだろう。

悲しみが来る、我々はそれを私たちはすべてのことを変更する方法を見つける聞かせて、拒否することはできません。今、私たちは、このコードを見てみましょう:

function add() {
    var a = 1;
    return function() {
        a++;
        console.log(a);
    }
}
var fn = add();
fn();   // 2
fn();   // 3
fn();   // 4

このコードは、ほとんどの魔法の場所、追加機能が完了すると、ローカル変数が破壊されていないのですが、それでもこれ何が起こったの最後に、存在していますか?私たちはゆっくりと分析してみましょう:

FNは=()を追加すると、FNは、関数に、この関数を参照を返し、ローカル変数が存在する
ローカル変数は、外部FN(によってアクセスすることができるので)、そこにそれを破壊する必要がないので、彼は保持

クロージャーは良いことですが、あなたはオンラインを含む多くの物事は、しばしば古典的なタイトルをテスト行うことができます

<ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        var aLi = document.getElementsByTagName('li');
        for (var i = 0; i < aLi.length; i++) {
            aLi[i].onclick = function() {
                console.log(i);     // ?
            };
        }
    </script>

この質問は本当にこの質問の目的は、クロージャの理解をテストすることで、あなたの手を上げてください観客に見られています。上記の答えは関係なく、結果は4ポイントではありませんか。
クリックがトリガされたときのonclickイベントは、リチウムの非同期ノードであるため、これは、サイクルが完成する雷の速度でベルを盗むために、私は4である変数の値がいる
ので、リーシスのイベント関数をクリックiは4であるから、私は内側から外側に探し始めるスコープチェーンは、すべての値を発見したときに
溶液が閉鎖を必要とする、各サイクルの値iが抑えれます。次に、スコープチェーンのルックアップをダウン継続するクリックイベントは、最初に私が見つけ脇に置かれるとき、各Liは、iの対応する値をクリックして見つけることができるように

<script>
        var aLi = document.getElementsByTagName('li');
        for (var i = 0; i < aLi.length; i++) {
            (function(n) {    // n为对应的索引值
                aLi[i].onclick = function() {  
                    console.log(n);     // 0, 1, 2, 3
                };
            })(i);  // 这里i每循环一次都存一下,然后把0,1,2,3传给上面的形参n
        }
    </script>

他のアクション

クロージャーが広く使用されている、我々はよく知られているについて言うためにここにいる、例えば、プライベート変数をパッケージ化することができ、あなたはグローバル公害変数を防ぐことができますプライベート変数にカプセル化されたグローバル変数へのいくつかの不要な露出を置くことができます

var sum = (function() {
    var cache = {};     // 将cache放入函数内部,避免被其他地方修改
    return function() {
        var args = Array.prototype.join.call(arguments, ',');
        if (args in cache) {
            return cache[args];
        }
        var a = 0;
        for (var i = 0; i < arguments.length; i++) {
            a += arguments[i];
        }
        return cache[args] = a;
    }
})();

また私は、多くの人々がこのようなjQueryのよういくつかのライブラリを見ていると信じて彼らの最も外側の層のような、次のコードに似ているアンダースコア

(function(win, undefined) {
    var a = 1;
    var obj = {};
    obj.fn = function() {};

    // 最后把想要暴露出去的内容可以挂载到window上
    win.obj = obj;
})(window);

はい、そうです、モジュラークロージャの使用を行うことができます。また、変数を拡張するために使用し、次に例を見てもよいです

var monitor = (function() {
    var imgs = [];
    return function(src){
        var img = new Image();
        imgs.push(img);
        img.src = src;
    }
})();

monitor('http://dd.com/srp.gif');

上記のコードは、ブラウザのいくつかの前に、状況はRBIの機能がIMGを完了された関数内のローカル変数をスペーススペースが破壊されるため、失われた、とこれを見える、RBIの統計データの場合であります可能な場合は、HTTPリクエストが発行されていません。
それはこれに来たときに、カプセル化された閉鎖IMGの変数は、解決することができます

メモリ管理

多くの人がそうクロージャの使用を最小限に抑えるために、その閉鎖のバージョンは、メモリリークが発生します聞いたことがある
:ちょうど今、あなたはそのように考えていないとして、正当化するために閉鎖に来ます

機能を破壊しなければならないローカル変数の実装を完了されていますが、ローカル変数は、クロージャ形成された環境の中にカプセル化されている場合は、ローカル変数が存在している可能性があること。以上の結果から、我々はそれが間違っていないと言って、練習を見に来る
しかし、クロージャを使用する理由私たちは、将来の使用を容易にするために、いくつかの変数を保存するためであり、メモリ上でこの分散型のグローバルな影響は同じです、メモリリーク考慮されていません。あなたが将来的にはnullに設定されている変数に直接これらの変数を回復したい場合は
、クロージャのスコープチェーンは、いくつかのDOMノードを保存する場合があり、この時点で、閉鎖は簡単です使用中に循環参照を形成していますこれは、メモリリークが発生することがあります。これは、それ自体閉鎖に問題はありませんが、jsの問題はありませんが、
IEのゲイバーの古いバージョンを非難し、その内部実装のガベージコレクションのメカニズムは参照カウント戦略を使用しています。2つのオブジェクトが循環参照との間に形成されている場合は、古い戦友IEでは、2つのオブジェクトが復元されるべきではなく、その性質上、間違ったに起因する循環参照メモリリークはの閉鎖ではない
循環参照メモリを解決するために、同じ代理店漏れの問題は、単に変数に循環参照がうまくnullに

上記は、我々は閉鎖のための名前何で、閉鎖は容易ではない、それはとの機嫌を取るませんでした。鍋ではないこと、それが戻ってする必要はありません理解されています!

おすすめ

転載: blog.51cto.com/14484771/2433755