js における関数のネストとクロージャの詳細

js における関数のネストとクロージャの詳細

序文:

今日は、クロージャについての私の理解についてお話しします。この問題について議論する前に、まず変数のドメインを理解しましょう。
js では、変数定義スコープにはグローバル スコープとローカル スコープが含まれます。 es6の新しい変数宣言キーワードは、いくつかの変数スコープの混乱を解決するために導入されました。グローバル スコープについてはここでは説明しません。主に関数の範囲について説明します。

1. 範囲

簡単に言えば、関数のスコープとは、関数の中括弧内のスペースのことです。まず、この概念をよりよく理解するのに役立つ 2 つの例を見てみましょう。

関数f1(){
  n = 999とする
  コンソール.log(n)
}
f1() // 999

関数f2(){
  n = 999とする
}
alert(n); // エラーメッセージ

2. 関数の戻り値

クロージャについて話す前に、関数の戻り値について話す必要があります。関数の戻り値に関しては、編集者は今年の初めに初めて理解が深まりました。戻り値のない関数は実行後にundefined返し、戻り値のある関数は実行後に該当する戻り値になります。こんな感じ

// 戻り値のない関数 function f1(){
  警告(666)
}
console.log(f1()) // ポップアップウィンドウが表示されたら、コンソールに undefined を出力します

// 戻り値関数 f2(){
  警告(666)
  'over' を返す
}
console.log(f2()) // ポップアップウィンドウが表示されたら、コンソールに出力します。もちろん、文字列、Bealon、または関数を返すこともできます。

3. 関数のネスト

「リファクタリング - 既存コードの設計を改善する」では、js 構文では関数内に関数をネストできると提案されていますが、すべてのプログラミング言語でこれができるわけではありません。いわゆるコードのネストとは、関数内に関数宣言があることを意味します。

このような:

関数outer(){
  名前を 'lilei' にします
  関数内部(){
    console.log(名前)
  }
}  

4. 終了

js におけるローカル変数スコープの問題については、以前に説明しました。実際のプロジェクトでは、関数の外部から関数内の変数にアクセスする必要があります。このとき、ローカル変数スコープの問題に対処する必要があります。不可能に思えますが、クロージャの出現によりこの問題は解決されます。

関数outer(){
  名前を 'lilei' にします
  関数内部(){
    戻り名
  }
  内部を返す
}

上記は典型的なクロージャ関数です。このクロージャ関数を使用すると、次のことができます。

g = アウター() とする
console.log(g()) // リレイ


これまでのところ、グローバル関数内でのローカル変数へのアクセスは解決されています。しかし、帰り道で、この機能を実現するために、このトラブルを回避することはできないだろうか? そういった機能を通じてニーズに応えることもできるのではないか? と考えていました。

関数outer(){
  名前を 'lilei' にします
  戻り名
}

console.log(outer()) // リレイ  


実際、上記のコードはクロージャを通じてコン​​ソールに出力されるものと同じなので、なぜクロージャを導入するのでしょうか?理解するのに 1 週​​間近くかかりました。変数 -> 関数 -> クラスのようなものです。レベルが上がるごとに、徐々に改善していきます。関数を通じて、変数だけでは実現できないデータ処理などのロジックをさらに実装できます。

5. クロージャの実用的応用

上記でエディターはクロージャを紹介しましたが、実際のプロジェクトではクロージャはどのように応用されるのでしょうか?まず次のコードを見てみましょう。

1. 内部変数名と関数実行の一時停止を非表示にする

関数outer() {
    名前を 1 にする
    関数内部() {
        名前を返す++
    }
    内部を返す
}
g = アウター() とする
コンソールログ(g()) // 2
コンソール.log(g()) // 3
コンソールログ(g()) // 4
コンソールログ(g()) // 5

2. setTimeout関数はパラメータを渡す

デフォルトの setTimeout は次のとおりです。

私も以前にこれを試したことがあります。

関数 f1(p) {
    コンソールログ(p)
}
setTimeout(f1(666),3000) // 遅延なし、666を直接出力

遅延を介して関数にパラメータを渡す場合、クロージャの役割が明らかになります。

関数 f1(a) {
    関数f2() {
        コンソールにログ出力します。
    }
    f2 を返します。
}
var fun = f1(1);
setTimeout(fun,1000); // 1秒後に1を出力します

3. コールバック

動作を定義し、それをユーザー イベント (クリックまたはキー押下) に関連付けます。コードは通常、コールバック (イベントがトリガーされたときに呼び出される関数) としてイベントにバインドされます。次のコードのように

<!DOCTYPE html>
<html lang="ja">
<ヘッド>
    <メタ文字セット="UTF-8">
    <title>テスト</title>
</head>
<本文>
    <a href="#" rel="外部 nofollow" rel="外部 nofollow" rel="外部 nofollow" id="size-12">12</a>
    <a href="#" rel="外部 nofollow" rel="外部 nofollow" rel="外部 nofollow" id="size-20">20</a>
    <a href="#" rel="外部 nofollow" rel="外部 nofollow" rel="外部 nofollow" id="size-30">30</a>

    <script type="text/javascript">
        関数 changeSize(サイズ){
            関数()を返す{
                document.body.style.fontSize = サイズ + 'px';
            };
        }

        var size12 = changeSize(12);
        var size14 = changeSize(20);
        var size16 = changeSize(30);

        document.getElementById('size-12').onclick = size12;
        document.getElementById('size-20').onclick = size14;
        document.getElementById('size-30').onclick = size16;
</スクリプト>
</本文>
</html>

4. 手ぶれ補正機能

コールバックはイベントがトリガーされてから n 秒後に実行されます。n 秒以内に再度トリガーされた場合は、タイミングが再開されます。

実装の鍵はsetTimeout関数にあります。タイミングを保存するための変数が必要なので、グローバルな純粋性を維持するために、クロージャを使用して実装できます。このような:

/*
* fn [関数] 手ぶれ補正を必要とする関数* delay [数値] ミリ秒、手ぶれ補正の期限値*/
関数デバウンス(fn,delay){
    let timer = null //クロージャ付き return function() {
        if(タイマー){
            clearTimeout(timer) //この分岐ステートメントを入力すると、タイミング プロセスが現在進行中であり、同じイベントが再度トリガーされることを示します。したがって、現在のタイミングをキャンセルしてタイミングを再開するには、timer = setTimeOut(fn,delay) を使用します。 
        }それ以外{
            timer = setTimeOut(fn,delay) // このブランチに入るということは、現在タイミングがないことを意味し、タイミングを開始します}
    }
}

6. クロージャ内の内部変数を隠すのと同様に、クラスを使用して関数を実装する

上記はクロージャの実際の応用です。夜眠れないときに、同じニーズを考えました。クラスで実装できるでしょうか?最終的に、多くの苦労の末、答えは「はい」です。

クラス Adder{
    コンストラクタ(c){
        this._c = c
    }
    増加(){
        これ._c++ 
    }
    減少(){
        this._c --
    }
    finalNum() を取得する{
        これを返します。_c
    }
}
c = new Adder(1) とする
c.増加()
コンソール.log(c.finalNum) // 2
c.増加()
コンソール.log(c.finalNum) // 3
c.増加()
コンソール.log(c.finalNum) // 4
c.減少()
コンソール.log(c.finalNum) // 3

参考記事:

https://www.cnblogs.com/gg-qq...

https://www.cnblogs.com/pikac...

https://developer.mozilla.org...

以下もご興味があるかもしれません:
  • JavaScript における関数のネスト
  • 1つの記事でJavaScriptのクロージャ関数について学ぶ
  • JavaScript クロージャの説明
  • Javascript のスコープとクロージャの詳細
  • JS の難しさ 同期と非同期、スコープとクロージャ、プロトタイプとプロトタイプ チェーンの詳細な説明
  • JavaScript のクロージャによって発生する問題を回避する
  • JavaScript のクロージャの問題の詳細な説明
  • JavaScript 関数の使用方法の詳細な説明 [関数の定義、パラメータ、バインディング、スコープ、クロージャなど]

<<:  CSS で水平方向と垂直方向に中央揃えする 10 の方法を教えます (要約)

>>:  ナビゲーションデザインと情報アーキテクチャ

推薦する

Vue-Jest自動テストの基本構成の詳しい説明

目次インストール構成よくある間違い事前テスト作業依存関係の扱いインスタンスとDOMを生成する要約する...

JavaScript の for ループと二重 for ループの詳細な説明

forループfor ループは配列の要素をループします。文法: for (初期化変数; 条件式; 繰り...

Nginx リバース プロキシ構成の完全なプロセス記録

1. 準備LinuxシステムにTomcatをインストールし、デフォルトのポート8080を使用してTo...

Python Django アプリケーションを Docker 化する方法

Docker は、開発者やシステム管理者がアプリケーションを軽量コンテナとして構築およびパッケージ化...

VMware マルチノード環境を構成する方法

このチュートリアルでは CentOS 7 64 ビットを使用します。各仮想マシンに 2GB のメモリ...

Linux jdk のインストールと環境変数の設定チュートリアル (jdk-8u144-linux-x64.tar.gz)

最初にsudo suコマンドを使用して root アカウントに切り替えることをお勧めします。そうしな...

Tomcat のプレースホルダーによるポート設定方法 (パラメータ指定方式)

仕事で必要になったため、インターネットで多くの情報を見つけましたが、それらはすべてコピーアンドペース...

vue3 プロジェクトを素早く構築し、関連機能を紹介する vite+ts の詳細な説明

目次ヴィテ建てる構成vite.config.tsルーターtsタイプvue3 の知識設定小道具コンテク...

Windows 10 Home Edition に Docker for Windows をインストールする

0. 背景ハードウェア: Xiaomi Notebook Air 13/Inter Core i7-...

上部の固定divは半透明効果に設定できます

コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBLIC "...

ReactでのDOM操作の実装

目次前の単語使用シナリオ参照HTML要素クラスコンポーネント機能コンポーネント[DOMノードを親コン...

MySQL パフォーマンス最適化のための魔法のツール、Explain の基本的な使用分析

導入MySQL には、SELECT ステートメントを分析し、開発者が最適化できるように SELECT...

Vueでシングルサインオンを実装する方法のまとめ

最近プロジェクトが中断され、RageFrame の研究は一時的に終了しました。この記事では、シングル...

jsはユーザーのページ操作を記憶するためにクッキーを使用します

序文開発プロセスでは、ブラウザレベルでユーザーが実行した操作を記憶するなど、同様の要件に遭遇すること...

ウェブデザインにおけるキーワード設計手法の紹介

多くの場合、ホームページを作成するときに、Web ページ ヘッダー属性の設定を無視します。 Web ...