반응형

안녕하세요. 신기한 연구소입니다.

자바스크립트를 공부하면 Scope(스코프)를 만나게 되는데요.

그중 렉시컬 스코프(lexical scope)의 의미가 참~이해하기 힘들더군요.

그래서 이번 포스팅은 렉시컬 스코프(lexical scope)를 나름 쉽게 정리해보려고 합니다.

그럼 같이 살펴보겠습니다.

 

자바스크립트(javascript)는 변수, 함수 등을 선언하고 사용합니다.

기본적으로 함수와 변수를 어디에 포함되지 않고(전역지역) 선언하면 전역 함수, 전역 변수가 됩니다.

전역이라면 어디서든 접근이 가능하다는 의미입니다.

하지만 함수 내부에 선언된 변수와 내부 함수는 지역 변수, 함수가 됩니다.

즉 부모 함수의 밖에서는 접근할 수 없게 됩니다.

부모 함수안에 자식 함수를 만들고 그 자식 함수 안에 손자 함수를 만든다고 가정한다면

손자 -> 자식 -> 부모 -> 전역으로 접근해서 사용할 수 있게 됩니다.

같은 전역 지역에 선언된 함수 A, B 2개가 있다면 서로 내부의 변수와 함수에 접근하거나 사용할 수 없습니다.

그냥 전역에 선언된 함수만 알 뿐이죠. 그 안의 변수와 함수는 다른 함수들이 알 수 없거든요.

예제 소스로 확인해보겠습니다.

1
2
3
4
5
6
7
8
9
10
var a = 1//전역 지역의 전역변수
 
function funcA() {  //전역 지역의 전역 함수
    console.log(a);
    return 2;
}
 
 
console.log(a);
console.log(funcA());
cs

 

1라인의 a는 전역 지역에 선언된 전역 변수입니다.

3라인의 funcA()는 전역 지역에 선언된 함수입니다.

4라인의 a는 전역 변수를 사용하고 있습니다.

실행 결과는 다음과 같습니다.

1
2
3
4
1
1
2
 
cs

9라인의 결과 1, 10라인의 결과는 함수를 호출해서 4라인의 1, 5라인의 2가 순서대로 출력되었습니다.

 

다음은 지역에 대한 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var a = 1//전역 지역의 전역변수
 
function funcA() {  //전역 지역의 전역 함수
    var a = 3;
    console.log(a);
    console.log(b);
    return 2;
}
 
function funcB() {  //전역 지역의 전역 함수
    var b = 4;    
    console.log(a);
    console.log(b);
    return 2;
}
 
console.log(a);
console.log(b);
console.log(funcA());
cs

이 예제는 오류가 발생합니다.

바로 6라인 때문입니다.

변수 b는 전역 지역의 다른 함수 funcB에 선언되어 있기에 

funcA에서는 접근할 수 없습니다. 

오류를 수정해봅니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a = 1//전역 지역의 전역변수
 
function funcA() {  //전역 지역의 전역 함수
    var a = 3;
    console.log(a);
    return 2;
}
 
function funcB() {  //전역 지역의 전역 함수
    var b = 4;    
    console.log(a);
    console.log(b);
    return 2;
}
 
console.log(a);
console.log(b);
console.log(funcA());
cs

이 코드 또한 오류가 발생했습니다.

바로 17라인 때문인데요.

변수 b는 funcA 함수내 지역 변수이기에 전역에서 바라볼 수 없습니다.

안에서 밖으로 바라볼 수 있지만 밖에서는 안으로 못 가는 상황이네요.

밖에서 (전역) 함수 내 선언된 변수(지역)을 바라볼 수 없다로 정리됩니다.

이 내용은 중요하니 잘 기억해두세요.

다시 오류를 수정해봅니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a = 1//전역 지역의 전역변수
 
function funcA() {  //전역 지역의 전역 함수
    var a = 3;
    console.log(a);
    return 2;
}
 
function funcB() {  //전역 지역의 전역 함수
    var b = 4;    
    console.log(a);
    console.log(b);
    return 2;
}
 
console.log(a);
console.log(funcA());
console.log(funcB());
cs

이제 오류 없이 실행이 됩니다.

결과는 어떻게 나올까요?

1
2
3
4
5
6
1
3
2
1
4
2
cs

1라인은 전역 변수 a를 출력합니다. 그래서 1.

2라인은 funcA에서 지역 변수 a를 출력합니다. 그래서 3.

3라인은 funcA의 return으로 2.

4라인은 funcB에서 전역 변수 a를 바라보기에 1입니다.

주의할 점은 funcA를 실행했고 a가 3으로 변할 거라 생각할 수 있지만 전역 변수 a를 바라봅니다.

이 설명을 다시하면

자바스크립트는 변수와 함수를 호출 시점에 선언하고 사용하는 것이 아닌

최초 로딩되는 순간 전역 지역 기준으로 바라보게 됩니다.

즉, 1라인의 변수 a, 함수 funcA, funcB는 전역 지역의 변수와 함수로

프로그램 실행 전 선언 단계에서 바라보게 됩니다.

하지만 funcA는 내부에 var a라고 지역변수를 선언했기 때문에

전역 변수 a가 아닌 지역 변수 a를 바라보게 되는 것이며

funcB에서 11라인의 console.log(a)는 로딩 때 이미 전역 변수 a를 바라보고

funcA 내부의 var a는 바라볼 수 없기에

funcA에서 var a = 3;으로 한다고 해서 전역 변수 a값이 재할당 되지는 않습니다.

 

전역 기준으로 선언이 되면 해당 전역 객체들을 기본적으로 바라보게 되고

함수 내 지역 변수가 선언되면 전역 기준으로 서로 내부는 들어갈 수 없게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = 1//전역 지역의 전역변수
 
function funcA() {  //전역 지역의 전역 함수
    var a = 3;
    console.log(a);
    return 2;
}
 
function funcB() {  //전역 지역의 전역 함수
    var b = 4;    
    console.log(funcA());
    console.log(b);
    console.log(a);
    return 2;
}
 
console.log(funcB());
cs

그럼 위 예제를 다시 보겠습니다.

funcB를 호출했습니다.

11라인으로 내부에서 전역의 funcA()를 호출했습니다.

내부에서는 로딩 때 이미 선언된 함수이기에 위로 바라보면서 funcA를 호출할 수 있습니다.

funcA는 지역 변수 var a를 할당했기에 전역 변수 a의 값 1이 아닌 3을 출력합니다.

이렇게 다른 함수의 내부 변수 값을 받을 수 있게 됩니다. 

그리고 return 2를 출력하고

12라인에서 b값 4를 출력합니다.

11라인에서 funcA를 호출해서 funcA의 지역 변수 a에 3으로 할당했지만

13라인은 전역 변수 a의 값 1을 출력합니다.

 

위 소스를 실행하면 자바스크립트 엔진은 먼저

전역 변수 a와 함수 funcA, funcB를 정의합니다.

그리고 funcA와 funcB 또는 전역 지역에서는 기본적으로 a를 찾으면 전역 변수 a를 바라봅니다.

이미 정의를 했기 때문이지요. (lexical scope or static scope)

하지만 함수 내부에서 같은 이름으로 지역 변수를 선언한다면 그 값을 바라보게 됩니다.

안에서 밖의 변수와 함수를 바라볼 수 있지만 반대로 접근은 할 수 없습니다.

 

렉시컬 스코프(lexical scope)를 풀어서 정의해보겠습니다.

변수나 함수가 전역 환경에서 선언이 되었다면 렉시컬 스코프(lexiclal scope)는 전역이 됩니다.

변수나 함수가 함수 내부처럼 지역 환경에 선언이 되었다면 해당 변수나 함수의 렉시컬 스코프(lexical scope)는

해당 함수의 지역이 됩니다.

이렇게 자바스크립트의 렉시컬 스코프를 나름 정리해봤습니다.

잘못된 정보나 혹은 다른 추가 정보가 있다면 정정하겠습니다.

즐 코딩하세요.

반응형
반응형

안녕하세요. 신기한 연구소입니다.

변수 이야기를 또 하게 되었습니다.

이번은 자바스크립트의 변수 이야기입니다.

변수의 특징에 대해 이해하고 호이스팅이 무엇인지 살펴볼까 합니다.

우선 변수에 대한 정의는 이전 포스팅을 참고하면 좋겠습니다. 

2021.05.30 - [Software/데이터베이스(SQL)] - [PLSQL]변수와 상수 친절한 설명으로 이해하기.

 

[PLSQL]변수와 상수 친절한 설명으로 이해하기.

안녕하세요. 신기한 연구소입니다. 변수와 상수에 대해 알아봅니다. 우선 간단하게 변수와 상수가 무엇인지 알아봅니다. 변수는 변하는 수입니다. 즉, 값을 바꿀 수 있다는 의미입니다. 빈 박스

tiboy.tistory.com

 

2021.08.01 - [Software/Java] - 변수와 객체 정리해 보기. 클래스 변수, 파라메터, 인스턴스 변수, 지역 변수, 전달 인자...

 

변수와 객체 정리해 보기. 클래스 변수, 파라메터, 인스턴스 변수, 지역 변수, 전달 인자...

안녕하세요. 신기한 연구소입니다. 프로그램을 개발하다 보면 변수에 대한 이름을 혼동해서 사용하는 경우가 종종 있습니다. 그래서 깔끔하게 정리해볼까 합니다. 우선 변수가 무엇인지 알아야

tiboy.tistory.com

 

프로그램은 다르더라도 변수의 개념은 같기에 미리 읽어보면 좋겠네요.

 

자바스크립트의 변수에 대한 이야기를 시작해봅니다.

먼저 자바스크립트의 변수는 일반적으로 var라는 키워드로 선언을 합니다.

ES6부터는 var의 구조적 문제의 해결을 위해 let과 const가 추가되었답니다.

간단하게 비교한다면...

var는 같은 변수명으로 중복 선언이 가능합니다.

let은 같은 변수명으로 중복 선언이 안됩니다.

const는 상수를 표현합니다. 즉 무조건 선언시 값을 할당해야 하고 이후 값을 변경할 수 없습니다.

예제.

결과.

위 예제처럼 firstVal은 중복 선언이 가능하고 오류가 나지 않습니다.

이렇게 짧은 코드는 개발자가 쉽게 인지하겠지만...

공통 작업을 하는 경우 엄청 길고 많은 코딩이 이루어질텐데

var로 중복된 변수를 선언해도 알기 힘들고 또한 잘못된 값이 전달될 수 있기에

문제가 발생하게 됩니다.

예제.

결과.

let의 경우는 중복 선언이 안된다고 했습니다.

위 예제에서 보듯 let으로 firstVal을 같은 이름으로 중복 선언하고 실행하니

이미 선언된 식별자(변수)라고 오류를 표시합니다.

예제.

결과.

이번 예제는 상수 const에 대한 부분입니다.

상수는 선언 시 무조건 값도 할당해야 합니다.

선언만 해서 초기 값이 빠졌다는 오류가 표시됩니다.

const도 중복 선언이 안되며 let과도 중복된 이름을 사용할 수 없습니다.

특히, var는 중복 선언이 가능하지만 그건 var끼리만 가능하고

const나 let과는 var라도 중복 선언을 할 수 없답니다.

예제.

결과.

const에 firstVal을 선언했기에 아무리 var라도 중복된 이름을 선언하니 오류가 납니다.

자바스크립트의 변수는 초기에 값을 설정하지 않으면 "undefined"라는 값이 할당됩니다.

undefined는 null도 아니고 빈 값 ""도 아닌 그냥 undefined입니다.

그래서 변수의 타입을 확인해봐도 undefined로 나타난답니다.

다음 예제로 확인해보겠습니다.

예제.

결과.

신기하네요.

그런데 뭔가 이상한 점이 있지 않나요?

자바스크립트 변수를 선언할 때는 var, let, const로 선언한다고 했습니다.

물론 위 선언문 없이 그냥 변수명만 써도 사용이 가능합니다.

그런데...

자바나 C 등의 프로그램은 변수를 선언할 때 타입으로 지정해서 하는데

자바스크립트는 그런 부분이 없습니다.

문자인지, 숫자인지, boolean인지 선언하지 않아도 자동으로 캐스팅이 된다는 겁니다.

즉, 선언하고 값을 할당할 때 자동으로 값에 맞는 타입이 된다는 의미입니다.

예제.

결과.

위 예제를 보면 numStr를 선언하고 값을 바꿀 때마다 해당 타입이 변경되는 부분을 확인할 수 있습니다.

자바스크립트의 변수는 먼저 사용하고 그 뒤에 선언해도 사용이 가능합니다.

예제.

결과.

위 예제를 보면 1번 라인에 score라는 변수의 값을 출력합니다.

결과는 undefined입니다.

4번의 출력 값은 80이 나오고 7번 또한 80이 나옵니다.

변수는 3번에서 할당했고 5번에서 선언을 했습니다.

그냥 보기에 혼란스럽네요.

 자바스크립트는 런타임 시점에 한 줄씩 순서대로 실행되는데,

변수 선언은 좀 다릅니다.

런타임 전 자바스크립트 엔진에서 먼저 선언된 변수들을 끌어올려(호이스팅)

실행을 하게 됩니다.

그 논리로 다시 위 예제를 보겠습니다.

var score가 5번에 있기에 먼저 실행하고 인지하게 됩니다.

그럼 1번 앞에 var score;가 오겠네요.

그리고 1번이 실행되면 아직 값이 할당 안되었기에 undefined로 할당돼서 결과가 나오게 됩니다.

그리고 3번에서 80으로 할당하게 됩니다.

그러면 4번에서 로그 출력 시 80으로 나오게 됩니다.

5번은 이미 1번 위로 선언되었기에 7번으로 가서 다시 80을 출력하게 됩니다.

이렇게 자바스크립트를 실행하면 자바스크립트 엔진에서 먼저 선언된 변수들을

쭉 끌어올려서 실행을 하는데 이것을 호이스팅(hoisting)이라고 합니다.

다른 프로그래밍 언어와는 조금 다른 방식의 변수 관리였습니다.

이 부분을 이해하기 위해서는 반드시 샘플을 다양하게 만들어서

확실히 이해하고 간다면

실전에서 개발하는 경우 로직의 이해나 오류에 대응할 때 도움이 될 것입니다.

내일 또 코딩 전쟁터로 떠나야겠네요.

즐 코딩하세요~~

반응형