Skip to content

Latest commit

 

History

History
207 lines (150 loc) · 6.82 KB

클로저-중첩-함수.md

File metadata and controls

207 lines (150 loc) · 6.82 KB

클로저 / 중첩 함수

Create Date: 2022/12/30
Update Date: 2022/12/30

노션에서 확인하기

저희는 이전에 스코프 4개를 배웠습니다.

  • 아시는 분….? 두 개씩 이야기해보아요 ㅎㅎ!
    • Global Scope, Script Scope, Function Local Scope, Block Scope

저희는 클로저를 알기 위해 스코프를 하나 더 알아야 합니다. 바로 어휘적 스코프입니다!

어휘적 스코프 (lexical scope)

간단합니다!

함수가 호출 시점의 스코프가 아니라 자신이 정의된 시점의 변수 스코프를 사용하여 실행된다는 뜻입니다. 기존 스코프들은 해당 변수를 사용할 수 있는 공간을 의미하는 scope였다면, 어휘적 스코프는 선언된 공간을 의미합니다.

const myName = 'Areum';

function getName() {
  return myName;
}

위 예제 myName의 어휘적 스코프는 어디일까요? myName은 전역 환경에서 선언되었기에 Global Scope(Script Scope)입니다.

function getName() {
  const myName = "Areum";
  return myName;
}
  • myName의 어휘적 스코프는 어디일까요?
    • getName()의 Local Scope 입니다. (Function Local Scope)
function showLastName() {
  const lastName = 'Sofela';
  return lastName;
}

function displayFullName() {
  const fullName = 'Oluwatobi ' + lastName;
  return fullName;
}

console.log(displayFullName()); // => ReferenceError: lastName is not defined

위 코드를 자세히 보겠습니다.

lastName displayFullName showLastName
어휘적 스코프 showLastName의 Local Global Scope Global Scope

현재 displayFullName에서 lastName을 가져오고 있지만 어휘적 스코프를 본다면 각각 다른 공간에 있는 것을 확인하실 수 있습니다.

이렇게 수정하면 어떨까요?

function showLastName() {
  const lastName = 'Sofela';
  return lastName;
}

function displayFullName() {
  const fullName = 'Oluwatobi ' + showLastName();
  return fullName;
}

console.log(displayFullName()); // => "Oluwatobi Sofela"
lastName displayFullName showLastName
어휘적 스코프 showLastName의 Local Global Scope Global Scope

위 코드에서 같은 어휘적 스코프에 있는 showLastName을 이용하여 lastName을 출력할 수 있게 되었습니다! 저희는 이미 클로저를 사용하였습니다.

클로저에 대해 더 자세히 알아봅시다!!!!

클로저

closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)

클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.
출처: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

말이 좀 어려운 것 같습니다. 코드와 함께 이해를 해보도록 하겠습니다.

let scope = 'global scope';

function checkScope() {
  let scope = 'local scope';
  function f() {
    return scope;
  }
  return f;
}

console.log(checkScope()()); // 여기는 어떤 값이 출력될까요?
  • 마지막 출력문에는 어떤 값이 출력될까요?
    • local scope

왜 위의 답이 나오게 되었을까요? 자바스크립트 함수는 어휘적 스코프를 준수합니다. 그렇기에 자신이 정의된 스코프에 실행되게 되죠.

그렇기에 f라는 함수는 console.log에서 실행된 것처럼 보여도 실제로는 checkScope 함수 안에서 실행이 된 것입니다. 간단히 말해 이것이 클로저의 강력함입니다.

scope checkScope checkScope > scope checkScope > f
어휘적 스코프 Global Scope Global Scope checkScope의 local checkScope의 local

위 mdn에서 다룬 말을 다시 정의해보자면 아래와 같습니다.

⛰️ 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수

즉, 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수 입니다.

엄밀히 말해 자바스크립트 함수는 모두 클로저입니다.

하지만 대부분의 함수가 자신이 정의된 곳과 같은 스코프에서 호출되므로 보통은 클로저인지 아닌지를 따질 필요가 없습니다.

클로저를 사용하면 함수 호출 시점의 로컬 변수를 캡처하므로 이 변수를 비공개 상태로 사용할 수 있습니다.

function counter() {
  let n = 0;
  return {
    log: function () {
      console.log(n);
    },
    count: function () {
      return n++;
    },
    reset: function () {
      n = 0;
    },
  };
}

const a = counter();
a.count();
a.reset();
a.log();

a.n; // => undefined

counter안의 n에 접근하는 방법은 return에 정의된 함수로만 임시로 접근할 수 있습니다.

중첩 함수 (Nested Funtion) = 내부 함수 (Inner Function)

let scope = 'global scope';
function checkScope() {
  let scope = 'local scope';
  function f() {
    return scope;
  }
  return f;
}

console.log(checkScope()()); // 여기는 어떤 값이 출력될까요?

저희가 위에서 다뤘던 함수 안에 함수를 적용하는 방식을 중첩 함수 혹은 내부 함수라고 부릅니다.

TMI) 스코프 체인

var a = 'global';

function outer() {
  var b = 'outer';

  function inner() {
    var c = 'inner';
  }
}

참고: https://www.youtube.com/watch?v=PVYjfrgZhtU

참고: https://www.youtube.com/watch?v=PVYjfrgZhtU

위 코드는 사진처럼 스코프 체인의 형태로 저장됩니다. 스코프 체인이 바인딩한 객체가 바로 렉시컬 스코프의 실체입니다.

참고 자료