Javascript-エンクロージャ

12817 ワード

Closerとは?


クローズドパッケージ(closure)とは、内部関数が外部関数にアクセスできる脈絡(context)であり、ある関数(outer)の内部で宣言された関数(inner)が外部関数を参照する領域変数(outer)が関数(outer)が終了しても変わらない現象を指す.
Closerは、JavaScriptを使って難易度の高いテクニックを使うために必要な概念です.


次のコードの結果は当然のエラーコードです.
名前変数outerの関数の실행 컨텍스트が終了すると、アクセスできる人はいません.関数の外でname変数を使用するには、モジュールを使用してアクセスします.
function outer(){
  const name = 'test'
  console.log(name)
}
outer() //test
console.log(name) //error
Closerの特性によって、内部関数が宣言されると、周囲の語彙環境(ここではouterのLexicalEnvironment)に縛られるからです.
したがって,内部で実行されてもLexicalEnvironmentが作成された後は参照されず,宣言時にバンドルされる.
function outer(){
  const name = 'test';
  console.log(name)
  return function inner(){
    const greeting = 'hello!'
    console.log(greeting,name)
  }
}
const getTest = outer() //test 
getTest() //hello!test
Lexical Environment
LexicalEnvironmentは、JS Engineが現在読んでいるコードのScopeまたはEnvironmentです.新しいLexicalEnvironmentは括弧の中に作成されます.Execution Contextは、JS Engineに現在のLexicalEnvironmentを提供し、使用可能な変数を決定します.LexicalEnvironmentは簡単に新しい世界と考えることができます.
const outer = () => {
  const outerVariable = 'outer!'; // 1. 바깥 함수 outer의 스코프에 변수선언

  const inner = () => {
    console.log(outerVariable); // 2. 내부 함수 inner의 스코프에서 스코프체인을 타고 바깥 함수 스코프의 변수 참조
  };

  return inner; // 3. 1급 시민인 함수 inner를 바깥으로 반환
};

const fano = outer(); // 4.  fano에 inner함수의 주소값이 저장됨

fano(); // 5. outer함수 호출은 종료가 되어서 스코프가 사라져야 하지만 outerVariable은 여전히 잘 참조된다.
外部関数が外部に返される内部関数は、外部関数の外部変数を参照するため、メモリに外部スキャンが保持されます.

適用


Closerを使用してPrivateメソッドを模倣することができます.プライベート・メソッドは、コードへの限られたアクセスを可能にするだけでなく、グローバル・ネーミング・スペースを管理する強力なメソッドを提供し、不要なメソッドが共通のインタフェースを乱すことを回避します.
次のコードでは、モジュールを使用してプライベート関数とアクセス変数の共通関数を定義する方法を説明します.このようにモジュールを使用することをモジュールモードと呼ぶ.
実例として,フロントエンドフレームワークReactのhook APIはカーネルによって実現される.hookは、関数を複数回呼び出した場合にデータの連続性を保つ機能です.
const counterCreator = () => {
  let value = 0;

  return {
    increase() {
      console.log(++value);
    },
    decrease() {
      console.log(--value);
    },
  };
};

const counter = counterCreator();

counter.increase(); // 1
counter.increase(); // 2
counter.decrease(); // 1
次の図に示すように、1つのCloser関数で2つのカウンタを生成し、独立したカウンタとして実行できます.
const counterCreator = () => {
  let value = 0;

  return {
    increase() {
      console.log(++value);
    },
    decrease() {
      console.log(--value);
    },
  };
};

const myCounter = counterCreator();
const yourCounter = counterCreator();

myCounter.increase(); // 1
myCounter.increase(); // 2
yourCounter.increase(); // 1
myCounter.decrease(); // 1
これにより,モジュールを用いてオブジェクト向けプログラミングの情報隠蔽やパッケージングなどの利点を得ることができる.

Reference


https://yuddomack.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%81%B4%EB%A1%9C%EC%A0%80Closure?category=754152
https://muscardinus.tistory.com/190
https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures