JavaScript Visualized: ⚡️⛓ Scope (Chain)

Posted on September 02, 2020  -  4 min read

reference: https://dev.to/lydiahallie/javascript-visualized-scope-chain-13pd

이번 포스트에선 스코프 체인🕺🏼을 다뤄 보겠습니다. 실행 컨텍스트에 대한 기본 지식을 전제로 합니다: 곧 다룰 예정입니다.😃


아래 코드를 한 번 봐주세요:

const name = "Lydia"
const age = 21
const city = "San Francisco"

function getPersonInfo() {
	const name = "Sarah"
	const age = 22
	
	return `${name} is ${age} and lives in ${city}`
}

console.log(getPersonInfo())

getPersonInfo함수를 호출하며, 해당 함수는 name, agecity변수를 포함하는 문자열을 반환합니다: Sarah is 22 and lives in San Francisco. 그러나, getPersonInfo함수는 city라는 변수를 포함하지 않고 있죠🤨? 어떻게 이 함수는 city의 값을 알고 있는 걸까요?

우선, 메모리 공간은 각각 다른 컨텍스트에 할당됩니다. 기본적인 전역 컨텍스트(브라우저 내에서 window입니다. Node에서는 global구요.)가 있고, 호출된 getPersonInfo함수를 위한 지역 컨텍스트가 있습니다. 각 컨텍스트는 스코프 체인을 가집니다.

getPersonInfo함수에 대한 스코프 체인은 이렇게 되어있습니다. (아직 이해가 가지 않더라도 걱정마세요):

scope chain 1

스코프 체인은 기본적으로 해당 실행 컨텍스트에서 참조할 수 있는 값(및 다른 스코프들)에 대한 참조를 포함하는 객체에 대한 “참조 체인” 입니다. (⛓: “이봐, 이것들은 해당 컨텍스트에서 네가 참조할 수 있는 모든 값들이야”.) 스코프 체인은 실행 컨텍스트가 생성될 때 만들어집니다. 즉, 런타임에 만들어진다는거죠!

그러나, 이 포스트에서 실행 컨텍스트나 activation object에 대해선 이야기하지 않겠습니다. 스코프에 집중을 해보죠! 예제를 보시면, 실행 컨텍스트의 키-값 쌍은 스코프 체인이 가지는 변수에 대한 참조를 나타냅니다.

scope chain 2

전역 컨텍스트의 스코프 체인은 3개 변수에 대한 참조를 가집니다: nameLydia란 값을 가지고, age21이란 값을 가지며, citySan Francisco란 값을 가집니다. 지역 컨텍스트에서는 2개 변수에 대한 참조를 가집니다: nameSarah란 값을 가지고, age는 값이 22죠.

getPersonInfo함수에서 변수에 대한 접근을 할 때, 엔진은 먼저 지역 스코프 체인을 확인합니다.

지역 스코프 체인은 nameage에 대한 참조를 가집니다! name은 값으로 Sarah를 가지고 age는 값이 22죠. 근데 지금, city에 접근할 때 어떤 일이 일어날까요?

city값을 찾기 위해 엔진은 “스코프 체인을 따라 내려갑니다.” 이것이 기본적으로 의미하는 바는 엔진이 쉽게 포기하지 않는다는 것이죠: 지역 스코프가 가진 참조하는 외부 스코프(이번엔 전역 객체)에서 city의 값을 찾을 수 있는지 알기 위해 노력하고 있습니다.

전역 컨텍스트에서 변수 citySan Francisco로 선언했으므로, city변수에 대한 참조를 가지죠. 이제 변수에 대한 값을 가지고 있으며, getPersonInfo함수는 문자열 Sarah is 22 and lives in San Francisco를 반환할 수 있습니다. 🎉


우리는 스코프 체인을 내려갈 수 있습니다. 하지만 스코프 체인을 거슬러 올라갈 수는 없죠. (몇몇 분들은 내려가는 것 대신 올라간다는 말이 헷갈릴 수 있을 거예요. 그러니까 다시 말해서, 외부 스코프로 갈 수 있지만 그 내부로는 갈 수가 없어요.) 전 이걸 일종의 폭포로 시각화 하는 걸 좋아합니다:

scope chain 5 또는 더 깊어진다면:

scope chain 6


예제로 이 코드를 보도록 하죠.

scope chain 7

거의 똑같은데, 하나 큰 차이가 있죠: 이번엔 city를 전역 스코프가 아닌 getPersonInfo함수 내에서 선언했습니다. 그리고 getPersonInfo함수를 호출하지 않으며, 지역 컨텍스트 또한 생성되지 않습니다. 하지만 여전히 전역 컨텍스트에서 name, agecity에 접근합니다.

이건 ReferenceError를 발생시킬거예요! 전역 스코프에서 city라는 변수에 대한 참조를 찾을 수 없고 찾아갈 외부 스코프도 없으며, 스코프 체인을 올라갈 수가 없으니까요.

이런 식으로 여러분들의 변수를 “보호”하고 변수명을 재사용하기 위해 스코프를 사용할 수도 있습니다.


Besides global and local scopes, there is also a block scope. Variables declared with the let or const keyword are scoped to the nearest curly brackets ({}).

글로벌과 지역 스코프 외에도, 블럭 스코프라는 것도 있습니다. letconst 키워드로 선언된 변수들은 가장 가까운 중괄호({ })에 대한 스코프를 갖습니다.

const age = 21
function checkAge() {
	if (age < 21) {
		const message = "You cannot drink!"
		return message
	} else { 
		const message = "You can drink!"
		return message
	}
}

스코프를 다음과 같이 시각화할 수 있습니다:

scope chain 9

전역 스코프, 함수 스코프와 두 개의 블럭 스코프가 있습니다. message 변수는 중괄호에 대한 스코프를 가지기 때문에 두 번 선언할 수 있습니다.


정리해 보겠습니다:

  • 스코프 체인은 현재 컨텍스트 내에서 접근할 수 있는 값들의 참조에 대한 체인입니다.
  • 스코프를 사용하여 스코프 체인에 추가로 정의된 변수명을 재사용 할 수 있습니다. 스코프 체인은 올라갈 수 없고 내려가는 것만 가능하기 때문입니다.

이것들이 스코프 (체인)에 대한 내용입니다! 사실 할 말이 더 많이 있어서 시간이 되면 추가 정보를 넣을 수도 있을 것 같아요. 어려운 점이 있으시면 자유롭게 질문해 주세요! 💕