TIL

0l0l·2021년 7월 17일
1

TIL

목록 보기
58/86

실행 컨텍스트 뿌시기🪓

실행 컨텍스트를 이해하면 자바스크립트 동작 방식, 코드의 실행 환경을 알 수 있다!
스코프와 렉시컬 환경과 연관지어 개념을 익혀야 한다.
자바스크립트를 이해하는데 필수 개념인 호이스팅, 클로저도 함께 이해하자!

스코프 체인(scope chain)

내부 함수는 외부 함수의 변수에 접근 가능⭕
외부 함수는 내부 함수의 변수에 접근 불가능❌
자기 자신의 스코프에서 변수를 찾지 못하면 상위 함수로 올라가면서(참조↑) 계속 범위를 넓히며 변수를 찾는 관계

렉시컬 스코핑(lexical scoping)

번역하면 어휘적 범위. 쉽게 정적 스코프라고 생각하자.

🤦‍♀️많이 헷갈리는 개념🤦‍♂️
스코프는 함수를 호출할 때가 아니라 '선언'할 때 생긴다.
함수를 처음 선언하는 순간, 함수 내부의 변수는 자기 스코프로부터 가장 가까운 곳(상위 범위)에 있는 변수를 계속 참조하게 된다.

실행 컨텍스트의 4가지 원칙

  • 먼저 전역 컨텍스트 하나 생성 후, 함수 호출 시 마다 컨텍스트가 생긴다.
  • 컨텍스트 생성 시, 컨텍스트 안에 변수 객체(arguments, variable), scope chain, this가 생성된다.
  • 컨텍스트 생성 후 함수가 실행되는데 사용되는 변수들은 변수 객체 안에서 값을 찾고, 없다면 스코프 체인을 따라 올라가며 찾는다.
  • 함수 실행이 마무리되면 해당 컨텍스트는 사라진다. 페이지가 종료되면 전역 컨텍스트가 사라진다.

🔽이해를 돕기위한 예시 코드

아래 코드를 보고 실행 순서를 예측해보자.
참고로 wow와 say 함수는 호이스팅 때문에 선언과 동시에 대입이 이루어졌다.

var name = 'brian'; // (1) 변수 선언 (6) 변수 대입

function hello(word) { // (2) 변수 선언 (3) 변수 대입
  console.log('Hello '+ name + ' I feel ' + word); // (11)
}

function say() { // (4) 변수 선언 (5) 변수 대입
  var name = 'ylyl'; // (8)
  console.log(name); // (9)
  hello('nice'); // (10)
}

say(); // (7)

호이스팅(hoisting)

변수를 선언하고 초기화했을 때 선언 부분이 최상단으로 끌어올려지는 현상이다.
함수 표현식(var 변수명 = function() {})이 아니라 함수 선언식(function 함수명() {})일때는 식 자체가 통째로 끌어올려진다.

함수 선언식¹ 에서 함수 선언식(function sayHi() {})과 변수 선언(var name = '';)이 최상단으로 끌어올려진다.
선언하기 전에 먼저 변수, 함수가 호출되어도 에러가 발생하지 않는다.

함수 표현식² 에서 함수 표현식(var sayYeah = function() {})은 선언과 대입이 동시에 이루어지지 않는다.
함수 선언식(function sayHello() {})은 선언과 동시에 초기화가 이루어진다. (호이스팅)
함수 표현식으로 작성된 함수를 선언하기 전에 먼저 호출하면 에러가 발생한다.

아래 코드는 동일한 코드를 함수 선언식과 함수 표현식으로 각각 작성한 코드이다.

// 함수 선언식¹
console.log(name); // undefined (error 아님)
sayHi(); // Hi (정상 출력)
function sayHi() {
  console.log('Hi');
}
var name = 'ylyl';

// 함수 표현식²
sayHello(); // (3)
sayYeah(); // (5) (대입되기 전에 호출 에러)
var sayYeah = function() { // (1) 선언 (6) 대입
  console.log('yeah');
}
function sayHello() { // (2) 선언+초기화 (호이스팅)
  console.log('hello'); // (4)
}

클로저(closure)

(한번에 이해하기 어려운 개념. 위의 개념들과 조합해서 이해하기😅)

함수와 렉시컬 환경의 조합.
함수가 생성될 당시의 외부 변수를 기억하고 생성 이후에도 (외부 변수에) 계속 접근이 가능하다.

외부 함수의 실행이 끝나서 외부 함수가 소멸된 이후에도
내부 함수가 외부 함수의 변수에 접근할 수 있다.
(스코프와 관련)

클로저를 통해 특정 변수를 은닉화할 수 있다.
전역 변수를 '함수로 감싸줌'으로써 함수 안에서만(클로저 함수의 지역변수) 접근이 가능하도록 한다.
외부에서는 접근 불가하므로 값을 바꿀 수 없다.


Q. 클로저를 사용하는 이유는?🧐
위에서 설명한 것과 같이 전역 변수로 선언하게 되면 어디서든 변수에 접근 가능하기 때문에 의도와 다르게 값이 변경될 수 있다.
(변수가 섞일 수 있기 때문인 이유에서라도 전역변수 생성하는 일은 최대한 지양하자.)

아래 코드에서 전역 변수 cnt를 함수 closure로 감싸서 클로저의 지역 변수로 만들어준다.
closure() 내부 함수들인 cntPlus(), setCnt(), printCnt() 외에는 cnt 변수 값을 바꿀 수 없다.

추가적인 기능이 필요할 때는 함수를 return하는 방식으로 원하는 기능을 구현한다.
클로저 함수의 지역 범위에 있는 함수들을 return해서 함수를 호출한다.
(일반적인 cntPlus();로 참조할 수 없다.)

function closure() {
  let cnt = 0; // 클로저의 지역 변수
  function cntPlus() {
    cnt += 1;
  }
  function setCnt(value) {
    cnt = value;
  }
  function printCnt() {
    console.log(cnt);
  }
  return {
    cntPlus,
    setCnt,
    printCnt,
  }
}

const cntClose = closure(); // 함수 closure의 리턴값을 변수에 할당
console.log(cntClose); // cntPlus, setCnt, printCnt
cntClose.printCnt(); // 0
cntClose.cntPlus(); // 값 변경
cntClose.printCnt(); // 1
cntClose.setcnt(100); // 값 변경
cntClose.printCnt(); // 100
profile
천방지축 빙글빙글

0개의 댓글