let username = 'JOYS';
if (username) {
let message = `Hello, ${username}!`;
console.log(message); // ?
}
console.log(message); // ?
--> Output
"Hello, JOYS!"
ReferenceError
왜 코드를 개발자 도구에 입력하면, Output과 같이 콘솔이 찍힐까?
똑같이 message를 출력할 것을 입력받았지만, 출력되는 결과값이 다른 것을 확인할 수 있다. 여기서 유추할 수 있는 것은 변수가 선언된 위치에 따라 접근가능범위(Scope)가 달라진다는 것이다.
첫 번째 message는 조건문(if) 안에서 선언되고, 선언된 변수, message와 같은 범위(Scope)에서 console.log()로 호출되었기 때문에 바깥에 선언된 username과 같은 범위에 선언된 message에 모두 접근 가능하기 때문에 "Hello, JOYS!"가 출력되었다.
반면, 두 번째로 호출된 message는 조건문의 바깥에서 호출이 실행되었는데, 전역변수로 선언된 username에는 접근 가능하겠지만, 조건문 안에서 변수가 선언된 message의 경우 그 조건문 바깥인 두 번째 message 호출에서는 접근이 불가능하다. 그래서 콘솔창에 찍히는 결과값은 ReferenceError가 된다.
ReferenceError 객체는 존재하지 않는 변수를 참조했을 때 발생하는 에러를 나타냅니다. - MDN
let welcome = 'Hello';
function welcomeForYou() {
let firstName = 'JOYS';
return welcome + ' ' + firstName;
}
console.log(welcomeForYou()); // ?
console.log(firstName); // ?
-->Output
'Hello Josh'
ReferenceError
이번에는 예시 1과는 차이가 있다. 두 콘솔 모두 함수라고 하는 범위 바깥에서 호출되었지만, 첫 번째는 함수 내부에서 선언된 firstName 에 접근하여 결과값을 도출해 내는 것을 보여준다. 반면 두 번째 호출은 함수 내에서 선언되었다는 이유로 firstName에 접근하지 못하고 ReferenceError가 출력된다.
이처럼 변수에 접근할 수 있는 범위가 존재하고, 이 범위를 스코프라고 부른다.
welcome 변수는 바깥에 정의되어 있으므로, 함수 안쪽에서 사용할 수 있다. 따라서 welcome 변수와 firstName 변수의 조합에 의해 'Hello JOYS' 문자열이 출력된다.
반면에 firstName 변수는 함수 안쪽에 정의되어 있으므로 함수 바깥쪽에서는 접근이 불가능하다. 따라서 ReferenceError를 출력한다.
예시 2에서는 변수의 접근 범위가 이번엔 함수에 의해 나누어진다. 범위가 중괄호(블록) 또는 함수에 의해 나누어지고, 그 범위를 스코프라고 부른다.
여기서 우리가 알 수 있는 규칙은 바로 다음과 같다.
바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능하다.
반면, 안쪽에서 선언한 변수는 바깥쪽 스코프에서는 사용할 수 없다.
위 사례와 분석을 통해 스코프의 정의를 좀 더 구체화하면,
"변수 접근 규칙에 따른 유효 범위" 라고 할 수 있다.