[programmers] TIL_DAY-14


✅ Closure


 Closerは前回整理したことがありますが、今度はもう一度整理します.エンクロージャを検索すると、次の定義が表示されます.
Closerは、関数と宣言されたときのLexical環境との組合せです.
 Closerは、JavaScriptでのみ使用される固有の概念ではなく、関数プログラミング言語で使用される重要な特性です.
function outFunction() {
  let x = 10;
  function inFunction() {
    console.log(x);
  }
  inFunction();
}
 このコードではinFunctionが関数スキャンを生成します.また、outFunction関数の内部で宣言されるため、scopeチェーンからoutFunction scopeに参照できます.したがって、x=10と宣言された値をinFunctionリファレンスで出力することができる.
function outFunction() {
  let x = 10;
  function inFunction() {
    console.log(x);
  }
  return inFunction;
}

let inner = outFunction();
inner();
 outFunctionを実行するとinFunction関数が返されます.戻るinnerを実行するとinFunction関数が実行され、10が出力されます.問題ないように見えますが、実は変なところがあります.outFunctionはinFunctionに戻り、完了(破棄)します.したがって,内部の変数xも無効となり,外部からxにアクセスできなくなる.ただし、inner()を実行すると、自然とx出力xの値が参照されます.
レクシー・カルスコフを覚えて!関数がどこで呼び出されたかではなく、関数が宣言された場所でスキャンされます.
 前回整理したラックスキャナーを覚えておけば分かりやすいです.InFunctionを呼び出すのはoutFunctionの外部であるグローバルレンジです.ただし、inFunctionを宣言する場所はoutFunctionの内部関数スキャンであり、スキャンチェーンを介してoutFunctionスキャンを参照することができる.
Closerとは,返される内部関数が自己宣言時の環境(LexicalEnvironment)を記憶し,自己宣言時の環境外で呼び出されてもその環境にアクセスできる関数である.簡単に言えば、エンクロージャは自分が生成した環境を記憶する関数です.
test = function() {
  for(var i = 0; i < 3; i++) {
    setTimeout(function() {
      console.log(i);
    }, 1000 * i);
  }
} 
 Closerを学ぶとよく出会うsettimootの例です.順次出力されると思いますが、実際には2が出力されます.
 どうしてこんなことになったの?JavaScriptエンジンでfor文を実行し、非同期コールバック関数settimeoutを実行します.したがって、for文はすべて実行され、iは2であり、settimeout実行時に参照されるiはすべて2である.この問題を解決するために、エンクロージャを使用する必要があります.
test = function() {
 for(let i = 0; i < 3; i++) {
   setTimeout(function() {
     console.log(i);
   }, 1000 * i);
 }
}

test = function() {
 for(let i = 0; i < 3; i++) {
   (function(x) {
     setTimeout(function() {
       console.log(x);
     }, 1000 * x);
   })(i);
  }
}
  letまたは即時実行関数を使用して、エンクロージャを作成します.letはブロックスキャン機能を有するため、各for文ループにはi値が格納される.すなわち、settimeout関数が実行されるたびに別のi値が出力されるモジュールが作成される.
エンクロージャは、安全にステータスを変更および維持するために使用されます.ステータスの予期せぬ変更を防止し、特定の関数のみがステータスを変更できるように、ステータスを安全に非表示にします.
let num = 0;

const increase = () => { return ++num };

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
 インクリメント関数を実行するとnumの値は正常に1インクリメントされ、出力されます.ただしnumは外部にあるので、他の場所で変更できます.関数を実行するたびにnumが値の前の値と同じであることは保証されません.
const increase = (function() {
  let num = 0;
  return function() {
    return ++num;
  }
})();

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
console.log(increase.num); // undefined
 モジュールを作成する実行関数をすぐに作成します.increateにはnumにアクセスできる匿名関数が返されます.したがって、numの値はこの匿名関数でのみ読み取りおよび変更できます.

整理する


  this、scope、closerを整理するとき、JavaScriptの動作原理は想像以上に複雑で、同じように重要だと感じます.モジュールを整理する過程で、「実行接触」という言葉がたくさん出てきたので、単独で整理する必要があります.本が来て、今はもっと簡単に勉強できるようになりました.😄