변수로 자바스크립트 이해하기
자바스크립트에서 변수는, 단순히 값을 설정하고 사용하는 개념에 그치지 않는다.
일반적으로 우리가 생각하는 변수는 int, string, date 등 데이터 타입들이 있다. 하지만 자바스크립트에서는 느슨한 데이터 타입이기에 모든 데이터 타입을 var로 지정할 수 있다. 따라서 문자열이나 숫자 뿐만 아니라, 객체나 함수도 변수로 지정한다.
이처럼 자바스크립트에서는 변수가 단순히 값을 설정하고 사용하는 개념에 그치지 않는다.
참조변수, 스코프, 클로저, 컨택스트, this 등도 자바스크립트를 제대로 이해하기 위한 핵심적인 개념을 담고 있기 때문에 반드시 이해하고 넘어가야 한다.
변수 선언
자바스크립트에서 변수는 선언하는 위치를 반드시 신경 써줘야 한다. 그 변수의 위치에 따라 의미하는 바가 완전히 달라지기 때문이다.
전역변수 or 지역변수
변수를 처음 접할 때, 가장 먼저 접하는 부분이 바로 전역변수인지, 지역변수인지에 대한 문제다.
이 말은, 코드의 모든 부분에서 접근하게 해줄 것인지(전역변수) 아니면 필요한 부분에서만 사용할 것인지(지역변수) 결정하는 부분이다.
프로그램 상에서 변수의 활용범위는 (전역변수 > 지역변수) 이지만, 변수의 영향력은 (전역변수 < 지역변수)다. 전역변수보다 지역변수가 우선순위를 가지게 된다.
함수 내부에서 선언된 변수는 지역변수로, 그 함수 안에서만 사용하겠다는 의미의 변수다. 단순히 그 함수 내에서만 사용되기 때문에, 프로그램의 전체 로직에 영향을 주지 않는다. 해당 함수의 로직에서만 영향을 주는 변수인 것이다.
보통 전역변수를 만들때는, 함수내부가 아닌 전역에서 var를 통해 변수를 선언한다. 하지만 대부분의 프로그래머는 실수로 인해 var를 사용하지 않고, 그냥 변수를 선언하면서 변수가 전역화 되는 경우도 있다.
변수 선언에 있어서 유념해야 하는 부분은 ‘변수의 선언 = 메모리’라는 개념이다. 전역변수를 무분별하게 선언하고 사용하면, 결국 메모리 누수가 발생되어 어플리케이션의 성능에 문제가 될 수 있다.
요즘은 브라우저 성능이 좋아져서 알아서 쓰지 않는 변수를 잘 정리해주지만, 그래도 쓸데없는 변수의 선언은 피하는 것이 좋다. 또한 전역변수를 함수의 여기저기서 접근하다 보면 의도치 않게 값이 변경되어 원하는 결과를 얻지 못할 수도 있다.
따라서, 전역스코프는 항상 깔끔하게 유지해두는 것이 좋다.
이 문제를 해결하기 위해 ES6부터는 const, let등의 추가적 변수를 선언하는 방법들이 소개되고 있다. 다음은 var, let, const의 차이점이다.
var | let | const | |
---|---|---|---|
전역 유효범위 | O | X | X |
함수 유효범위 | O | O | O |
블록 유효범위 | X | O | O |
재할당 가능 | O | O | X |
let과 const는 블록 레벨 스코프로, 블록 안에서만 값이 작용된다.
let a = 111;
{
let a = 222;
let b = 222;
}
console.log(a); // 111
console.log(b); // b is not defined
b는 블록 안에 있기 때문에 밖에서 값을 정의할 수 없고, a는 밖에 선언된 111값이 나온다.
- let은 변수 중복 선언 불가
var a = 111;
var a = 222;
console.log(a); // 222
----------------------------------
let a = 111
let a = 222 // Error
- let은 호이스팅 불가 (호이스팅은 아래에 설명)
console.log(a);
var a;
출력값 : undefined
---------------------------------
console.log(b); // Error
let b;
- const는 재할당 불가능
let은 변수의 재할당이 가능하지만, const는 불가능
let a = 111;
a = 222; // 222로 변경
const b = 111;
b = 222; // Error
유효 범위(scope)가 자바스크립트에서 어떤 의미를 가지는지에 대해서 알아보자.
유효 범위(scope)
우리는 변수가 전역과 지역이라는 특정한 범위에서 유효한 영향을 가진다는 것을 알게 되었다. 이제 변수의 유효한 범위를 스코프라고 부를 것이다.
스코프의 핵심은 ‘함수단위의 유효범위’이다.
이 한 줄로 모든 것을 설명할 수 있다. 즉, 어떤 함수에 정의된 변수는 해당 함수 내에서만 유효한 값을 행사한다는 의미다.
아래와 같은 코드를 살펴보자.
function callYOU(){
var myname = “james”;
callAdam();
}
function callAdam(){
return myname;
}
callYOU();
결과가 어떻게 리턴될까? james가 나올 것이라고 예상할 수 있지만, 에러가 발생한다.
우리는 callAdam을 호출하는 시점에, myname 변수가 함수 내에 선언이 되어있고 난 후에 호출하기 때문에 myname 변수에 접근할 수 있을 것이라 생각할 수 있다. 하지만 에러가 발생한다.
왜냐하면, 변수는 함수가 호출하는 시점이 아닌 함수가 정의 되는 시점에 생성되기 때문이다.
callAdam이 정의되는 시점에 myname이라는 변수는 callYOU 함수 안에서만 존재한다. 따라서 myname은 당연히 지역변수다. 즉, 외부 함수에서는 접근이 안되는 변수다.
지금은 함수의 정의 시점에 따라 접근가능한 변수가 달라진다는 말이 이해가 잘 되지 않을 수 있다. 하지만 앞으로 배울 실행컨택스트의 변수객체와 this의 개념을 이해하면 자연스럽게 따라올 것이다.
일단은, 유효범위는 함수 단위로 정해진다라고 이해하고 넘어가자.
호이스팅
자바스크립트에는 호이스팅이라는 개념이 있다. 이는 변수의 선언과 변수의 할당을 구분하겠다는 개념이다. 즉, 함수 내에서 선언된 어떤 위치의 변수든 함수의 최상단으로 끌어올려진다. 그리고 undefined로 임의의 값으로 할당이 된다. 그리고 나중에 함수가 실행이 되면서 그 변수에 해당하는 값을 할당하는 것이다. 예를 들어보자.
function hoistingTest(){
console.log(’greeting : ’ + hi);
var hi = “hello”;
console.log(’greeting : ’ + hi);
}
hoistingTest()
출력값
greeting : undefined
greeting : hello
위 코드가 호이스팅을 설명하는 가장 일반적인 코드다. 위의 코드는 분명히 에러가 나와야 한다. 왜냐하면 hi라는 변수가 선언 되지도 않았는데, hi 변수를 선언해서 사용하고 있다. 그런데 실행해보면 에러가 나지 않는다. 즉, 변수의 선언이 호이스팅에 의해서 맨 위로 끌어올려지기 때문이다. 변수 값의 할당은 해당 코드로 내려오면서 실행이 이루어진다. 이것이 자바스크립트의 호이스팅 개념이다.
실행 컨택스트
이제는 변수는 물론이고, 자바스크립트를 이해하는 핵심이 되는 실행컨택스트에 대한 내용이다.
자바스크립트에서 코드는 크게 세가지로 분류된다.
1) global 코드
2) function 코드
3) eval 코드
이 모든 코드는 실행 컨택스트로 들어와 실행이 이루어진다. 즉, 자바스크립트에서 실행되는 모든 것을 관리하는 부분이 바로 실행 컨택스트다.
global 컨택스트는 오직 하나만 존재하지만, function, eval 컨택스트는 하나의 프로그램에 여러개가 존재할 수 있다.
실행 컨텍스트는 스택이라는 영역에 저장된다. 스택에는 나중에 들어온 컨택스트가 스택의 최상단에 위치하고, 현재 실행되고 있는 컨택스트를 callee라고 부른다. 그리고 실행 컨택스트 내에서 다른 컨택스트를 실행시키기 위해 필요한게 caller다.
즉 쉽게 표현하면, caller가 컨택스트를 실행하면, 기존에 caller가 동작시키고 있던 실행의 흐름이 새롭게 동작하는 callee로 변경된다. 이 callee는 실행 컨택스트의 최상단에 위치하게 되고, Active 컨택스트라는 이름을 갖는다.
이러한 작업을 계속 거치면서 callee가 스택에 쌓이게 되고, 동작을 마친 예전 callee는 간단하게 return하거나 exit하게된다.
자바스크립트를 다루는 개발자들이 면접을 볼 때 많이 받는 질문이 있다. undefined와 not defined의 차이에 대해 설명하는 것이다.
다음과 같은 코드가 있다.
console.log(A) // undefined
console.log(B) // error
B = "not defined";
var A = "undefined"
우선 해당 컨택스트로 들어가보자. 이때 변수객체는 다음과 같다.
변수객채 = {
A : undefined
}
B는 변수 객체가 존재하지 않는다. 왜그럴까? 자바스크립트는 모든 변수가 var를 통해서만 생성된다는 것을 배웠었다. 즉, var를 통해서 선언된 변수만이 변수 객체에 추가될 수 있는 자격이 있다.
B의 경우에는 객체의 프로퍼티로 추가되어버린다. 우리에게 변수는 변수객체 내에 선언된 프로퍼티라는 사실을 명심해야 한다.
따라서 위 코드는 다음과 같이 수정해야 에러가 나지 않는다.
console.log(A)
B = "not defined";
console.log(B)
var A = "undefined"
var가 아닌 B 변수는 미리 선언을 해주어야, 실제로 코드가 실행이 되는 단계에서 전역객체의 프로퍼티 접근 개념으로 값을 불러오게 되는 것이다.
'Angular' 카테고리의 다른 글
Angular 개발 툴 및 모듈 설명 (0) | 2018.04.04 |
---|---|
Angular CLI를 통한 프로젝트 시작하기 (0) | 2018.04.04 |
[타입 스크립트] 기본 개념 정리 (0) | 2018.04.04 |
[앵귤러] 컴포넌트 사용하기 (0) | 2018.04.04 |
[앵귤러] 기초 정리 (0) | 2018.04.04 |