ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript のクロージャを理解する

JavaScript のクロージャを理解する

PHPz
PHPzオリジナル
2024-08-24 11:11:021045ブラウズ

Understanding Closures in JavaScript

クロージャは JavaScript の基本的な概念であり、コードの記述方法と理解方法に大きな影響を与える可能性があります。本質的に、クロージャを使用すると、外部関数の実行が終了した後でも、関数はその外部スコープから変数にアクセスできます。この機能は非常に強力ですが、効果的に使用するにはしっかりした理解も必要です。詳細を見ていきましょう。

クロージャとは何ですか?

クロージャは、それが作成された語彙環境をキャプチャする関数です。これは、外部関数の実行が完了した後でも、関数はその外部スコープから変数へのアクセスを保持することを意味します。 JavaScript では、関数が別の関数内で定義されるたびにクロージャが作成されます。

基本的な例

クロージャを理解するために、簡単な例を考えてみましょう:

function outerFunction() {
    let outerVariable = 'I am an outer variable';

    function innerFunction() {
        console.log(outerVariable); // Inner function can access the outer variable
    }

    return innerFunction;
}

const myClosure = outerFunction();
myClosure(); // Logs: "I am an outer variable"

この例では:

  1. externalFunction は、ローカル変数 externalVariable と内部関数 innerFunction を宣言します。
  2. innerFunction は、outerVariable をログに記録し、外部変数へのアクセスを示します。
  3. externalFunction は innerFunction を返し、クロージャを作成します。
  4. innerFunction への参照を保持する myClosure は、outerFunction が終了した後でも、outerVariable にアクセスできます。

字句のスコープとクロージャ

JavaScript の字句スコープとは、関数のスコープが呼び出される場所ではなく、関数が定義される場所によって決定されることを意味します。クロージャはこのスコープ メカニズムを利用し、外部関数が戻った後でも関数が外部スコープから変数にアクセスできるようにします。

実践例: プライベート変数

クロージャは、プライベート変数を作成するためによく使用されます。プライベート変数は、その変数を含む関数の外部からアクセスできない変数です。

function createCounter() {
    let count = 0;

    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1

こちら:

  1. createCounter は count を初期化し、インクリメント メソッドとデクリメント メソッドを使用してオブジェクトを返します。
  2. 両方のメソッドは、カウントを取得して変更するクロージャを形成しますが、カウントは非公開のままです。

高度な例: イテレータ

クロージャを使用して、関数呼び出し全体で内部状態を維持するステートフルなイテレータを作成することもできます。

function createIterator(array) {
    let index = 0;

    return {
        next: function() {
            if (index < array.length) {
                return { value: array[index++], done: false };
            } else {
                return { value: undefined, done: true };
            }
        }
    };
}

const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

この例では:

  1. createIterator はクロージャ内の配列とインデックスをキャプチャします。
  2. 次のメソッドは、キャプチャされたインデックスを使用して配列要素を 1 つずつ返します。

よくある落とし穴: ループ内のクロージャ

クロージャーをループ内で使用すると、特に非同期操作で予期しない動作が発生することがあります。この問題を示す例は次のとおりです:

var の使用
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// Logs: 5 5 5 5 5

この場合:

  1. ループが完了し、i は 5 になります。
  2. すべての setTimeout コールバックは同じ i、つまり 5 を参照します。
letの使用
for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// Logs: 0 1 2 3 4

こちら:

  1. let は反復ごとに新しいブロックスコープの i を作成します。
  2. 各 setTimeout コールバックは異なる i をキャプチャし、期待どおりの出力が得られます。

まとめ

  • クロージャ: 語彙環境を記憶し、その語彙環境にアクセスできる関数。
  • 字句スコープ: 関数は、呼び出されるのではなく、定義された場所に基づいてスコープされます。
  • プライベート変数: クロージャは変数をカプセル化して保護できます。
  • イテレータ: クロージャは状態を維持し、データへの順次アクセスを提供します。
  • ループの落とし穴: ループ内の var には注意し、予期しない動作を避けるために let を優先してください。

クロージャとそのニュアンスを理解すると、より強力で保守しやすい JavaScript コードを作成する能力が高まります。これらの原則を賢明に使用すると、クロージャを活用して複雑な問題を効果的に解決できるようになります。

Github Linkedin でフォローしてください

以上がJavaScript のクロージャを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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