JavaScriptのクロージャ.


閉鎖とは
クロージャは、その語彙の環境と一緒に関数のバンドルです.
より単純な条件では、関数が実行されると、その周辺の状態(語彙環境)をチェックし、それらの変数が実行されたブロックの後でさえ、将来的にそれらを必要とすると思われるなら、どんな変数にでも保持します.
ここで、関数はその変数への参照を保持し、実際の値自体ではなく、親スコープも含みます.
したがって、実行後にブロックを終了した後でも変数を保持する連続スコープは、将来参照することができます.
このスコープは、関数が存在し続ける限り、プライベート変数が存在します.
すべてのJavaScript開発者は、この概念が存在しなかったにもかかわらず、閉鎖に遭遇している.
より良い方法でこの概念を説明するいくつかの例を解決しよう.
簡単なものから始めましょう.
let outer= function(){
    let a=5,b=20
    function insideOuter(){
        return a+b
    }
    return insideOuter
}



let outputOne=outer()
console.log(outputOne)
console.log(outputOne())



--output on console is ---
ƒ insideOuter(){
        return a+b
    }
25.
上記を参照すると、insideexternalという別の関数を返します.
私たちは、これを必要に応じて呼び出すことができるように、これをoutputoneという変数に渡します.
アウトプットが呼び出されたとき、InsideOutside関数は呼び出されます.これは外部関数スコープに依存して呼び出されます.
それで、閉鎖は既にそのブロックで形成されます.
しかし、それが形成されたかどうかを知っていますか?我々カント右それを参照してください?実際に我々はできます.
デバッガを10行目または4行目に配置し、コンソールを監視します.

あなたが慎重に観察するならば、それはそれが外側の機能範囲で閉鎖を形成したことを示します.
さて、私が言ったように、このスコープは必要に応じて親スコープも含みます.それでは、コードにいくつかの手順を加えましょう.

let outer= function(){
    let a=5,b=20
    function insideOuter(){
        let c=7.5
        function innerMost(){
            return (a+b+c)
        }
        return innerMost        
    }
    return insideOuter
}




let outputOne=outer()
console.log(outputOne)

let outputTwo=outputOne()
console.log(outputTwo)

let result=outputTwo()
console.log(result)

ここでは、外側の関数を返します.
我々が知っているように、この形閉鎖.return関数がコールされると、最も内側の別の関数が返されます.
この最も内側の最初は、内側の範囲で閉鎖を形成します.しかし、そのスコープには、独立して正しく実行するために必要なすべての変数がありません.それで、それはもう一つのレベルより上に見えて、それが閉鎖を形成するとわかりました.

上記のイメージでは、最も内側が外側と外側の機能環境/範囲で閉鎖を形成しているので、我々ははっきりとわかることができます.
したがって、Output 2を関数として実行するとき、1000行のコードの後でも、スコープはまだ持続します.
これがその例です.

別の例を見てみましょう.

let multiplier =factor=>{
    return number=>{
        return number*factor
    }
}


let thrice=multiplier(3)
let thriceOfFive=thrice(5)
console.log(thriceOfFive)


---output on console ---
15

ここで,匿名関数は,乗数機能環境で閉包を形成し,可変因子に保持する.

別の例を見てみましょう.
閉じるこの動画はお気に入りから削除されています.
settimeout関数は、クロージャが形成される方法を混乱させることができます.実際、それは私たちを混乱させるでしょう.


for(var i=0;i<3;i++){
    function one(){
        console.log(`${i} from function one`)
    }
    const two=()=>{
        console.log(`${i} from function two`)
    }
    setTimeout(two,1000)
    one()
}


ここではforループを作成し、すべての反復処理のために内部で定義された関数を呼び出し、出力をログ出力します.
機能の仕事は簡単です.その特定の時点でi変数を持つ文をログに記録する必要があります.
コードをよく見て、出力を推測してください.
あなたは、出力がこれであるかもしれないと思うかもしれません.私も同じように思った

0 from function two
0 from function one
1 from function two
1 from function one
2 from function two
2 from function one

または何か他のが、実際の答えはこれです.

でもどうして?何が起こったの?なぜ私たちもこのような出力を得るのですか?
これは2つの理由からです.
まず最初に、JavaScriptはSetTimeoutで宣言された時間を待ちません.代わりに、処理される必要があるデータと一緒にタイマーをとって、それをどこかに格納して、プログラムの残りで続けてください、そして、一旦タイマーがそれを処理するならば、データのその部分を処理します.
そして、これは主な問題の原因です.タイマーが期限切れになると、JavaScriptが待機していないので、すでにループを通して実行され、結果として値が更新されますが、関数2が他の関数が実行されたときに、値が更新されます.
二つ目の理由は、varキーワードを使用して変数** i * *を宣言しているためであり、それはブロックスコープではないスコープスコープの関数のみです.だから私はここで世界的な空間です.それで、それが常に利用できるように、それはどんな閉鎖も形成する必要はありません.
それで、私がグローバルであるので、機能2は同じ参照を指し示します、そして、タイマーが期限が切れるとき、その特定の時点でi値は記録されます.
それから、どのように我々は機能2を保持する出力を得るか?シンプル.必ず閉鎖が形成されることを確認します.これを行うには、letキーワードを使用して変数を宣言します.


for(let i=0;i<3;i++){
    function one(){
        console.log(`${i} from function one`)
    }
    const two=()=>{
        console.log(`${i} from function two`)
    }
    setTimeout(two,1000)
    one()
}


letはブロックスコープであるため、関数はそのブロックでクロージャを形成します.それで、現在、我々は以下のように出力を得ます.

下記を見ると、変数iがvarを使用して宣言されたとき、それはグローバルなスペースにあります.

一方、Letの両方の関数を使用して変数iを宣言したときに、クロージャを閉じています.つまり、各関数コールの新しいリファレンスを指します.

これはクロージャが何であるかです.

閉じるこの動画はお気に入りから削除されています.違いはJavaScriptが私たちのためにこの仕事をするということです.
お読みいただきありがとうございます.
すべてのフィードバックは非常に有り難いです.
ハッピーコーディング.🤎