[자바스크립트 개발자라면 알아야 할 33가지 개념] #6 함수와 블록 스코프 (번역)

이윤우·2023년 4월 13일
0

JavaScript

목록 보기
24/34
post-thumbnail

스코프(Scope)

자바스크립트에서 스코프는 어떤 변수에 접근할 수 있는지를 정의합니다. 일반적으로 2가지의 스코프가 존재합니다. 전역 스코프와 지역 스코프가 존재하죠.

지역 스코프(Local Scope)

1) 함수 스코프 지역 변수

함수 내에서 변수를 선언했을 때, 우리는 함수 안에서만 이 변수에 접근할 수 있습니다. 우리가 함수 밖으로 나오게 된 이후에는 함수 내부에 있는 변수에 접근할 수 없습니다.

function sayHello() {
	const hello = 'Hello';
  	console.log(hello);
}

sayHello(); // Hello
console.log(hello); // Error, hello is not defined

2) 블록 스코프(Block Scope)

우리가 변수를 {} 괄호 안에 constlet 키워드로 선언했을 때, 우리는 {} 괄호 안에서만 이 변수에 접근할 수 있습니다.

{
	const hello = 'Hello';
  	console.log(hello); // Hello
}

console.log(hello); // Error, hello is not defined

함수 호이스팅과 스코프

function 키워드와 함께 선언된 함수들은 항상 현재 스코프의 가장 위로 호이스팅됩니다.
그래서 다음 코드의 결과는 같습니다.

sayHello();
function sayHello() {
	console.log('Hello');
}

sayHello();

함수 표현식으로 작성된 함수들은 현재 스코프의 가장 위로 호이스팅 되지 않습니다.

함수는 각자의 스코프에 접근할 수 없다.

함수를 각각 선언했을 때, 함수는 다른 함수의 스코프에 접근할 권한을 갖고 있지 않습니다. 심지어 함수 내에서 다른 함수를 불러오더라도 스코프는 사용할 수 없습니다.

내부 스코프(Nested Scope)

함수가 다른 함수 안에서 만들어졌고 안쪽 함수는 바깥 함수의 변수에 접근 가능합니다. 이러한 것을 렉시컬 스코프(lexical scoping)라고 합니다.
하지만 바깥 함수에게는 안쪽 함수의 변수에 접근할 권한이 주어지지 않습니다.

클로저(Closures)

우리가 함수 안에서 또다른 함수를 만들 때마다 사실 우리는 클로저를 만든겁니다. 안쪽 함수가 클로저입니다. 일반적으로 반환시키기 위해서 클로저를 만듭니다. 우리는 반환된 클로저를 이용하여 바깥 함수의 변수들을 사용할 수 있습니다.

function outerFunction() {
	const outer = 'I see the outer variable';
  	
  	return function innerFunction() {
    	console.log(outer);
    }
}

outerFunction()();

클로저는 바깥 함수의 변수에 접근할 수 있기 때문에 주로 두가지 이유로 쓰입니다.
1. 사이드 이펙트(side effects)를 제어하기 위해서

사이드 이펙트
사이드 이펙트란 어떤 함수 내에서 자신의 스코프가 아닌 변수를 제어하는 것을 말합니다.

  1. private 변수를 만들기 위해서

클로저로 사이드 이펙트 제어하기

함수에서 값을 반환하는 것과는 별도의 무언가를 하는 경우 사이드 이펙트가 발생할 수 있습니다. Ajax 요청, timeout, 심지어 console.log 문까지 많은 것들이 사이드 이펙트를 유발할 수 있습니다.

function (x) {
	console.log('A console.log is a side effect!');
}

사이드 이펙트를 제어하기 위해 클로저를 사용할 때, 우리가 만든 Ajax나 timeout과 같은 코드를 망칠 수 있는 것을 고려해야 합니다.

친구의 생일을 위해 생일 케이크를 만들고 싶다고 가정해보겠습니다. 이 케이크를 만드는데 1초가 걸립니다. 그래서 우리는 1초 후에 made a cake를 로깅하는 함수를 만들었습니다.

function makeCake(){
	setTimeout(_ => console.log('Made a cake', 1000);
}

이 함수는 timeout이라는 사이드 이펙트를 가지고 있습니다.
이제 추가로 친구에게 케이크의 맛을 고르게 해봅시다.

function makeCake(flavor) {
	setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000);
}

여기서 문제는 우리가 케이크의 맛을 안 뒤에 바로 만들고 싶지는 않다는 것입니다. 시기가 적절할 때 만들고 싶다는 것입니다.
이 문제를 해결하기 위해, 우리는 우리의 맛을 저장할 수 있는 prepareCake 함수를 작성할 수 있습니다. 그 후 prepareCake 내부에 makeCake 클로저를 반환할 수 있습니다.

function prepareCake(flavor) {
	return function () {
    	setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000);
    }
}

const makeCakeLater = prepareCake('banna!');

makeCakeLater();

이게 사이드 이펙트를 줄이기 위해 클로저가 사용되는 방법입니다. 이제 당신이 내키는대로 내부 클로저를 사용하는 함수를 만들 수 있습니다.

클로저로 private 변수 만들기

지금까지 배워 알고 있듯, 함수 내부에서 만들어진 변수는 바깥 변수에서 접근할 수 없습니다. 이러한 이유로 그 변수들은 private 변수라고 불립니다.

하지만, 때때로 우리는 private 변수에 접근할 필요가 있습니다. 우린 클로저를 이용하여 private 변수에 접근할 수 있습니다.

function secret(secretCode){
	return {
    	saySecretCode() {
        	console.log(secretCode);
        }
    }
}

const theSecret = secret('CSS Tricks is amazing');
theSecret.saySecretCode()

위 예제에서 saySecretCode는 유일하게 기존 secret 함수 밖에서 secretCode를 노출하는 함수입니다. 보통 이러한 경우, 이 함수는 preivileged function이라 불립니다.

0개의 댓글