JavaScriptのクロージャ.
12826 ワード
閉鎖とは
クロージャは、その語彙の環境と一緒に関数のバンドルです.
より単純な条件では、関数が実行されると、その周辺の状態(語彙環境)をチェックし、それらの変数が実行されたブロックの後でさえ、将来的にそれらを必要とすると思われるなら、どんな変数にでも保持します.
ここで、関数はその変数への参照を保持し、実際の値自体ではなく、親スコープも含みます.
したがって、実行後にブロックを終了した後でも変数を保持する連続スコープは、将来参照することができます.
このスコープは、関数が存在し続ける限り、プライベート変数が存在します.
すべてのJavaScript開発者は、この概念が存在しなかったにもかかわらず、閉鎖に遭遇している.
より良い方法でこの概念を説明するいくつかの例を解決しよう.
簡単なものから始めましょう.
私たちは、これを必要に応じて呼び出すことができるように、これをoutputoneという変数に渡します.
アウトプットが呼び出されたとき、InsideOutside関数は呼び出されます.これは外部関数スコープに依存して呼び出されます.
それで、閉鎖は既にそのブロックで形成されます.
しかし、それが形成されたかどうかを知っていますか?我々カント右それを参照してください?実際に我々はできます.
デバッガを10行目または4行目に配置し、コンソールを監視します.
あなたが慎重に観察するならば、それはそれが外側の機能範囲で閉鎖を形成したことを示します.
さて、私が言ったように、このスコープは必要に応じて親スコープも含みます.それでは、コードにいくつかの手順を加えましょう.
我々が知っているように、この形閉鎖.return関数がコールされると、最も内側の別の関数が返されます.
この最も内側の最初は、内側の範囲で閉鎖を形成します.しかし、そのスコープには、独立して正しく実行するために必要なすべての変数がありません.それで、それはもう一つのレベルより上に見えて、それが閉鎖を形成するとわかりました.
上記のイメージでは、最も内側が外側と外側の機能環境/範囲で閉鎖を形成しているので、我々ははっきりとわかることができます.
したがって、Output 2を関数として実行するとき、1000行のコードの後でも、スコープはまだ持続します.
これがその例です.
別の例を見てみましょう.
別の例を見てみましょう.
閉じるこの動画はお気に入りから削除されています.
settimeout関数は、クロージャが形成される方法を混乱させることができます.実際、それは私たちを混乱させるでしょう.
機能の仕事は簡単です.その特定の時点でi変数を持つ文をログに記録する必要があります.
コードをよく見て、出力を推測してください.
あなたは、出力がこれであるかもしれないと思うかもしれません.私も同じように思った
でもどうして?何が起こったの?なぜ私たちもこのような出力を得るのですか?
これは2つの理由からです.
まず最初に、JavaScriptはSetTimeoutで宣言された時間を待ちません.代わりに、処理される必要があるデータと一緒にタイマーをとって、それをどこかに格納して、プログラムの残りで続けてください、そして、一旦タイマーがそれを処理するならば、データのその部分を処理します.
そして、これは主な問題の原因です.タイマーが期限切れになると、JavaScriptが待機していないので、すでにループを通して実行され、結果として値が更新されますが、関数2が他の関数が実行されたときに、値が更新されます.
二つ目の理由は、varキーワードを使用して変数** i * *を宣言しているためであり、それはブロックスコープではないスコープスコープの関数のみです.だから私はここで世界的な空間です.それで、それが常に利用できるように、それはどんな閉鎖も形成する必要はありません.
それで、私がグローバルであるので、機能2は同じ参照を指し示します、そして、タイマーが期限が切れるとき、その特定の時点でi値は記録されます.
それから、どのように我々は機能2を保持する出力を得るか?シンプル.必ず閉鎖が形成されることを確認します.これを行うには、letキーワードを使用して変数を宣言します.
下記を見ると、変数iがvarを使用して宣言されたとき、それはグローバルなスペースにあります.
一方、Letの両方の関数を使用して変数iを宣言したときに、クロージャを閉じています.つまり、各関数コールの新しいリファレンスを指します.
これはクロージャが何であるかです.
閉じるこの動画はお気に入りから削除されています.違いは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が私たちのためにこの仕事をするということです.
お読みいただきありがとうございます.
すべてのフィードバックは非常に有り難いです.
ハッピーコーディング.🤎
Reference
この問題について(JavaScriptのクロージャ.), 我々は、より多くの情報をここで見つけました https://dev.to/belidenikhil/closures-in-javascript-4nl6テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol