JavaScript の高度なクロージャの説明

JavaScript の高度なクロージャの説明

1. 閉鎖の概念

一般的な機能の実行とインスピレーションを見てみましょう。

        関数stop() {
            var 数値 = 0;
            console.log(数値);
        }
        stop(); // num が 0 であることを出力します
        console.log(num); // エラー報告関数が定義されていません

1. この時点では関数内の変数は関数外からアクセスできない

2. 関数内で定義された変数は常に存在するわけではなく、関数が終了すると消えます。

閉鎖の概念:

1. 別のスコープ内の変数にアクセスできる関数です。

2. 別の言い方をすると、内部関数の有効期間が外部関数の宣言有効期間よりも長く、内部関数が何らかの方法で外部スコープからアクセスされる場合、クロージャが作成されるということです。

次のクロージャ コードと説明を見てみましょう。

        関数fn() {
            var 数値 = 10;
            // 関数 fun() {
            // コンソール.log(数値);
 
            // }
            // fun を返します。
            関数を返す(){
                console.log(数値); // 10
            }
        }
        var f = fn();
        関数f();

これをいくつかの部分に分けることができます。

1. fn 関数は内部の戻り値を持ち、関数です。

2. return 関数は内部の num 変数を出力します。 num 変数が出力できる理由は、スコープ チェーンのアクセス メカニズムによるものです。以下では、スコープとスコープ チェーンの知識ポイントを補足します。

3. f変数を使用してfn()を外部的に受け入れます。つまり、fn[内部関数]の戻り値を受け入れます。

4. 次に f が呼び出されます。これは、fn 内の内部関数が呼び出されることを意味します。最終的に10を印刷できる

追加の知識ポイント:

1. 範囲:

変数は特定の範囲内で動作し、この範囲外では効果がありません。この範囲が範囲です。スコープは関数が呼び出されたときではなく、関数が定義されたときに作成されます。

2. スコープチェーン:

一言でまとめると、「内部関数は外部関数変数にアクセスできる」という考え方に基づき、近接原則を採用して、変数をレイヤーごとに検索します。このメカニズムはスコープ チェーンと呼ばれます。

関数 A に関数 B が含まれている場合、関数 B は関数 A の内部関数になります。

内部関数が変数を使用する場合、まずその内部にそのような変数が存在するかどうかを確認します。

そうでない場合は、次のレベルを検索します。[近接の原則]

関数がレイヤーごとに見つからない場合は、最終的にグローバル変数の下で検索されます。

        var a = 1;
        var b = 11;
        関数fn1() {
            var a = 2;
            var b = '22';
            関数fn2();
            関数fn2() {
                var a = 3;
                関数fn3();
                関数fn3() {
                    var a = 4;
                    コンソールログ(a); // 4
                    console.log(b); // '22'
                }
            }
        }
        関数fn1();

3. ガベージコレクションのメカニズム

JS ガベージ コレクション メカニズムに関するこのビッグ ブラザーの説明を参照できます。

//www.jb51.net/article/229425.htm

これら3つの概念を組み合わせて、閉鎖の役割を見てみましょう。

2. 閉鎖の役割:

関数 A を外部関数と呼び、この関数内に関数 B があります。

関数A [関数B]の戻り値を受け取るために外部で変数fを使用する

関数Aのスコープ内の変数はnumと呼ばれます

1. 関数の外部から関数内の変数にアクセスできるようにする [内部スコープへの外部アクセス用のチャネルを構築する]

原則:実際には上記で説明しました。

まず、上に示した一連の動作の原理を理解する必要があります。関数Bは関数Aの変数numを呼び出すことができる

2 番目に理解すべきことは、まず、関数 A の戻り値は関数 B [内部関数] であり、次に、この戻り値は関数外部の変数 f で受け取られる必要があるということです。それを受け取った後、関数 B を呼び出すことができ、関数 B は関数 A の変数 num にアクセスします。そして、この内部関数 B が閉鎖関数です。

2. 関数内の変数のライフサイクルを延長できます。

最初の効果は 2 番目の効果をもたらします。 js 変数にはガベージ コレクション メカニズムがあります。関数が実行されると、変数はクリアされ、メモリが削除されます。ただし、クロージャが使用されている場合、変数はすぐにクリアされない可能性があります。

その理由は、外部変数 f が関数 A の内部関数 B を受け入れ、この内部関数が関数 A のスコープ内の変数 num にアクセスするためです。関数 B が実行され、変数 f が存在する限り、変数 num は常に存在します。関数 A の実行が終了しても消えることはありません。

非常に詳しく解説されているので、以下の記事も参考にしてください。

JavaScript クロージャの説明

3. 閉鎖例

クロージャのいくつかのアプリケーションは後で追加されます。

クロージャをいつ使用するかを覚えておき、乱用しないようにする必要があります。

3.1 liをクリックすると現在のliのインデックス番号が出力されます。

    <ul class="nav">
        <li>ドリアン</li>
        <li>臭豆腐</li>
        <li>ニシンの缶詰</li>
        <li>大きな豚足</li>
    </ul>
    <スクリプト>
        // クロージャの適用 - li をクリックすると、現在の li のインデックス番号が出力されます // 1. 属性を動的に追加するメソッドを使用できます var lis = document.querySelector('.nav').querySelectorAll('li');
        (var i = 0; i < lis.length; i++) の場合 {
            lis[i].onclick = 関数(){
                console.log(i); // 4 つの 4
            }
        }
    </スクリプト>

原理:上の図をこのように書くと、印刷される i は常に 4 になります。その理由は、この時点では非厳密モードになっているからです。非厳密モードでは、for ループは同期実行タスクですが、ボタンのクリックは非同期タスクです。同期実行が完了すると、i に 4 が加算されます。次に、非同期タスクは i を出力しますが、これは常に 4 です。

解決策1: クロージャを使用する

1. forループは4つの即時実行される関数を生成する

2. 即時に実行される関数はクロージャのアプリケーションです。 [クリック コールバック] 関数を含む即時実行関数内のすべての関数は、即時実行関数によって渡されたパラメータを使用できます。

        (var i = 0; i < lis.length; i++) の場合 {
            (関数 (i) {
                // コンソールログ(i);
                lis[i].onclick = 関数(){
                    コンソールにログ出力します。
 
                }
            })(私);
        }

変更2: var--->let

対応する小さな li をクリックし、対応するインデックス番号である i を印刷します。 letの使用はES6構文であり、forはブロックレベルのスコープを持ちます。

        var lis = document.querySelector('.nav').querySelectorAll('li');
        (i = 0 とします; i < lis.length; i++) {
            lis[i].onclick = 関数(){
                // コンソールログ(i);
                コンソールにログ出力します。
            }
        }

方法3: カスタム属性インデックスを設定する方法を使用する

        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) { // これはletではなくvarであることに注意してください
            lis[i].index = i; // これはthis.indexではなくlis[i]であることに注意してください。この時点ではクリックは行われていないので、これはどこから来るのでしょうか?
            lis[i].onclick = 関数(){
                コンソールにログ出力します。
            }
        }

要約する

この記事はこれで終わりです。皆さんのお役に立てれば幸いです。また、123WORDPRESS.COM のその他のコンテンツにも注目していただければ幸いです。

以下もご興味があるかもしれません:
  • JSにおけるクロージャの役割について詳しく話しましょう
  • JavaScriptクロージャの原理と機能の詳細な説明
  • JavaScript クロージャの詳細
  • JavaScript クロージャの説明
  • JavaScriptのクロージャとは何かを学びましょう

<<:  HTMLで細い線のテーブルを作成する簡単な例

>>:  ウェブページの背景画像を伸ばす2つの方法

推薦する

Vue は検証コードのカウントダウンボタンを実装します

この記事では、検証コードカウントダウンボタンを実装するためのVueの具体的なコードを例として紹介しま...

Ubuntu 16.04 で PostgreSQL の起動を設定する方法

PostgreSQL はコンパイルされインストールされるため、起動時に起動するように設定する必要があ...

CentOS 7 に MySQL 8.0.20 データベースをインストールするための詳細なチュートリアル

関連記事: MySQL8.0.20 インストール チュートリアルとインストールの問題に関する詳細なチ...

MySQL の binlog ログと、binlog ログを使用してデータを回復する方法を説明します。

ご存知のとおり、binlog ログは MySQL データベースにとって非常に重要です。万が一、データ...

Docker コマンドラインの完全ガイド (知っておくべき 18 のこと)

序文Docker イメージは Dockerfile といくつかの必要な依存関係で構成され、Docke...

MySQL クエリのパケットが大きすぎる問題と解決策

問題の説明:エラーメッセージ:原因: com.mysql.jdbc.PacketTooBigExce...

Mysql の大きな SQL ファイルの高速リカバリ ソリューションの共有

序文MySQL データベースを使用する過程では、データベースのバックアップと復元が必要になることがよ...

MySQL のフィールドに一意のインデックスを追加および削除する方法

1. PRIMARY KEY(主キーインデックス)を追加するmysql>ALTER TABLE...

win10 64 ビット システムに複数の JDK バージョンをインストールする際の切り替え問題と解決策の概要

コンピューターにmyeclipse2017とidea2017がインストールされているため、ideaが...

MySQLの半同期の詳細な説明

目次序文MySQL マスタースレーブレプリケーションMySQL でサポートされているレプリケーション...

MySQLの読み書き分離により挿入後にデータが選択されなくなる問題を解決

MySQLは独立した書き込み分離を設定します。コードに次のものを書くと問題が発生する可能性があります...

Linux で boost.python を使用して C++ 動的ライブラリを呼び出す方法

序文最近、C++ 動的ライブラリをテストするためにロボット フレームワークを使い始めました。ロボット...

MySQLクエリ速度を最適化する方法

前の章では、高性能な MySQL に不可欠な、最適化されたデータ型の選択方法とインデックスの効率的な...