Language/Java Script

클로저(Closure)

원2 2024. 7. 25. 18:10
728x90
반응형

- 주변 상태에 대한 참조와 함께 묶인 함수의 조합, 내부 함수에서 외부 함수의 범위에 대한 접근 제공

js에서 클로저는 함수가 생성될 때마다 생성됨

 

- 오직 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있음

어휘적 범위 지정 (Lexical scopeing)

function init() {
  var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수
  function displayName() {
    // displayName() 은 내부 함수이며, 클로저
    console.log(name); // 부모 함수에서 선언된 변수를 사용
  }
  displayName();
}
init();

ex2

function outerFunction() {
  let outerVariable = 'I am outside!';
  
  function innerFunction() {
    console.log(outerVariable); // outerFunction의 스코프에 있는 outerVariable에 접근
  }
  
  return innerFunction;
}

const closureFunction = outerFunction();
closureFunction(); // "I am outside!" 출력

 

ex3

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12

- 당연히 서로 다른 환경을 가짐

 

클로저를 이용, private method 흉내내기

- 모듈 디자인 패턴,

const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.

 

클로저 스코프 체인

세가지 스코프

  • 지역 범위(Local Scope, Own scope)
  • 포함하고 있는 범위 (블록, 함수, 모듈 범위)
  • 전역 범위
// 전역 범위 (global scope)
const e = 10;
function sum(a) {
  return function (b) {
    return function (c) {
      // 외부 함수 범위 (outer functions scope)
      return function (d) {
        // 지역 범위 (local scope)
        return a + b + c + d + e;
      };
    };
  };
}

console.log(sum(1)(2)(3)(4)); // 20
// 전역 범위 (global scope)
const e = 10;
function sum(a) {
  return function sum2(b) {
    return function sum3(c) {
      // 외부 함수 범위 (outer functions scope)
      return function sum4(d) {
        // 지역 범위 (local scope)
        return a + b + c + d + e;
      };
    };
  };
}

const sum2 = sum(1);
const sum3 = sum2(2);
const sum4 = sum3(3);
const result = sum4(4);
console.log(result); // 20

*  위의 함수들은 전부 외부함수의 범위에 접근중임

 

 

블록 범위의 변수 캡처

function outer() {
  let getY;
  {
    const y = 6;
    getY = () => y;
  }
  console.log(typeof y); // undefined
  console.log(getY()); // 6
}

outer();

 

 

모듈 범위의 변수 캡처

// myModule.js
let x = 5;
export const getX = () => x;
export const setX = (val) => {
  x = val;
};

 

import { getX, setX } from "./myModule.js";

console.log(getX()); // 5
setX(6);
console.log(getX()); // 6

 

 

루프에서 클로저 생성

 

function showHelp(help) {
  document.getElementById("help").textContent = help;
}

function setupHelp() {
  var helpText = [
    { id: "email", help: "Your e-mail address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (var i = 0; i < helpText.length; i++) {
    // 범인은 이 줄에서 `var`를 사용하는 것입니다.
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function () {
      showHelp(item.help);
    };
  }
}

setupHelp();

 

이 코드에서 var를 사용해서 원하는 텍스트가 안나오고 맨 마지막 텍스트가 나오는데

var 가 함수형 스코프이기 때문임.

 

해결책 1

function showHelp(help) {
  document.getElementById("help").innerHTML = help;
}

// 클로저 생성
function makeHelpCallback(help) {
  return function () {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = [
    { id: "email", help: "Your e-mail address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp();

 

해결2 (항목의 현재 값이 포함된 즉각적인 이벤트 리스너 추가)

function showHelp(help) {
  document.getElementById("help").innerHTML = help;
}

function setupHelp() {
  var helpText = [
    { id: "email", help: "Your e-mail address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (var i = 0; i < helpText.length; i++) {
    (function () {
      var item = helpText[i];
      document.getElementById(item.id).onfocus = function () {
        showHelp(item.help);
      };
    })(); // 항목의 현재 값이 포함된 즉각적인 이벤트 리스너 추가(반복될 때까지 보존됩니다).
  }
}

setupHelp();

 

 

해결3 클로저를 사용하지 않고 let const 를 사용(블록 스코프)

function showHelp(help) {
  document.getElementById("help").textContent = help;
}

function setupHelp() {
  const helpText = [
    { id: "email", help: "Your email address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (let i = 0; i < helpText.length; i++) {
    const item = helpText[i];
    document.getElementById(item.id).onfocus = () => {
      showHelp(item.help);
    };
  }
}

setupHelp();

 


 

*함수 스코프 - 변수가 함수 내에서만 유효한 범위를 가짐

function exampleFunction() {
  var functionScopedVariable = 'I am a function scoped variable';
  
  if (true) {
    var insideBlock = 'I am still function scoped';
    console.log(functionScopedVariable); // 접근 가능
  }
  
  console.log(insideBlock); // 접근 가능
}

exampleFunction();
console.log(functionScopedVariable); // 오류: 함수 외부에서는 접근 불가

 

*블록 스코프 - 변수가 블록 내에서만 유효한 범위를 가짐

function exampleFunction() {
  let blockScopedVariable = 'I am a block scoped variable';
  
  if (true) {
    let insideBlock = 'I am block scoped';
    console.log(blockScopedVariable); // 접근 가능
    console.log(insideBlock); // 접근 가능
  }
  
  console.log(insideBlock); // 오류: 블록 외부에서는 접근 불가
}

exampleFunction();
console.log(blockScopedVariable); // 오류: 함수 외부에서는 접근 불가

 

예전에 어떤 개발자 오픈카톡에서 누가 블록안에 코드를 넣으라는데 블록이 어딘지 모르겠다길래

블록은 { } 이거다 라고 하니까 사람들이 아니라고.. 다른거 같은데요??? 다른 코드도 보여주실래요??? 요ㅈㄹ..하길래..

할 말을 잃고 조용히 방을 나왔던 기억이 난다..

 

 

728x90
반응형

'Language > Java Script' 카테고리의 다른 글

여러조건 비교 includes  (0) 2024.09.05
프로토타입과 클래스  (0) 2022.06.04
배열 내장함수  (0) 2022.06.04
반복문 for...in  (0) 2022.06.03
reduce  (0) 2022.05.20
spread 와 rest  (0) 2022.05.19