
let, const, var)와 스코프와의 관계를 설명할 수 있다.변수(variable)의 유효 범위를 뜻한다.
현재 실행되는 컨텍스트라고도 설명 가능하며, 컨텍스트는 값과 표현식이 "표현"되거나 참조될 수 있음을 뜻한다. 만약 변수 또는 다른 표현식이 "해당 스코프"내에 있지 않다면 사용할 수 없다.
var scope = 'global scope';
function foo () {
var scope = 'function scope';
var name = 'jun';
console.log(scope);
}
foo(); // ?
console.log(scope); // ?
console.log(name); // ?
foo()
함수 foo는 변수 scope 를 출력하는 함수이다. 하지만 scope 는 전역에서 한번, 지역에서 한번 선언되어있다. 이 같은 경우 우선순위는 지역변수가 더 높으므로 'function scope' 가 출력되게 된다.
console.log(scope)
변수 scope 를 출력하는 코드이다. 이 코드는 함수 밖에서 작성되었고 그렇기에 지역변수를 출력하는 것이 아닌 전역변수를 출력하게된다.
그러므로 'global scope' 가 출력되게 된다.
console.log(name)
변수 name 을 출력하는 코드이다. 하지만 name 은 foo 함수 내에서 선언되었기 때문에 지역변수이고, 전역변수엔 존재하지 않는다. 그렇기에 스코프의 규칙에 따라 ReferenceError: name is not defined 라는 오류가 출력된다.
자바스크립트에서 스코프를 구분해 보면 다음과 같이 2가지로 나뉜다.
변수 또한 스코프를 갖는다. 변수의 관점에서 스코프를 구분하면 2가지로 나뉜다.
{...})을 기준으로 범위를 구분한다.if (true) {
// this is block scope
}
for (let i = 0; i < 10; i++) {
// this is block scope
}
{
// this is block scope
}
function 키워드가 등장하는 함수 선언식 및 함수 표현식에서 만들어진다.function foo() {
// this is function scope
}
let bar = function () {
// this is function scope
}
❗️ 여기서 주의할 점은 화살표 함수는 블록 스코프로 취급된다.
let foobar = () => {
// this is block scope
}
var 와 let , const다음 코드를 보자
for (let i = 0; i < 5; i++) {
console.log(i); // 다섯번 반복
}
console.log('final i: ', i); // ReferenceError
블록 스코프 내에서 선언한 i 가 스코프 바깥에서 호출되었기 때문에 ReferencError 오류가 발생한다.
for (var i = 0; i < 5; i++) {
console.log(i); // 다섯번 반복
}
console.log('final i: ', i); // output : 5
변수 i 는 블록 스코프 안에서 선언되었는데 스코프 바깥에서 사용할 수 있었다.
이와 같이 var 키워드로 선언한 변수는 블록 스코프를 무시하고, 함수 스코프만 따른다.
이 때, 화살표 함수의 블록 스코프는 무시하지 않는다.
또한 var 키워드는 let 과 달리 재선언이 가능하다
var num = 1;
var num = 2; // 재선언 가능
let num2 = 1;
let num2 = 2; // SyntaxError: Identifier 'num2' has already been declared
const 키워드 또한 let 과 비슷하나 값의 재할당이 불가능하다. 변하지 않는 값, 즉 상수(constant)를 정의할 때 사용한다.
정리해서 보자면 다음과 같다.
| let | const | var | |
|---|---|---|---|
| 유효 범위 | 블록 스코프 및 함수 스코프 | 블록 스코프 및 함수 스코프 | 함수 스코프 |
| 값 재할당 | 가능 | 불가능 | 가능 |
| 재선언 | 불가능 | 불가능 | 가능 |
let name = 'jun';
function foo() {
let name = 'JUN';
bar();
}
function bar() {
console.log(name);
}
foo(); // output : 'jun'
bar(); // output : 'jun'
위 코드의 실행 결과는 함수 bar 의 상위 스코프가 무엇인지에 따라 결정된다. 다음과 같이 두가지 패턴을 예측할 수 있다
첫번째 방식을 따른다면 bar 의 상위 스코프는 함수 foo 와 전역일것이다.
두번째 방식을 따른다면 bar 의 상위 스코프는 전역일것이다.
첫번째 방식을 동적 스코프(Dynamic scope) 라고 하며
두번째 방식을 렉시컬 스코프(Lexical scope) 또는 정적 스코프(Static scope) 라고 한다.
JavaScript의 경우 렉시컬 스코프를 따르기 때문에 선언한 곳에 따라 스코프가 정해진다. 전역에서 선언된 bar 의 상위 스코프는 전역 스코프가 되어 name 의 값이 'jun'이 된다.
let num1 = 1; // 전역 변수
function foo () {
num2 = 2; // 선언되지 않은 식별자
console.log(num1 + num2);
}
foo(); // output : 3
위 코드에서 num2 는 선언하지 않은 식별자이다.
하지만 오류 없이 num2 는 선언된 변수처럼 동작하여 더하기 연산이 실행되었다.
선언하지 않은 식별자에 값을 할당하면 전역 객체의 프로퍼티가 된다.
즉 num2 = 2 를 window.num2 = 2 로 해석하여 프로퍼티를 동적 생성한다.
결국 num2 는 전역 객체의 프로퍼티가 되어 마치 전역 변수처럼 동작한다.
이러한 현상을 암묵적 전역(implicit global)이라 한다.
참고 : Scope - PoiemaWeb