#1. 자바스크립트 소개
#2. 자바스크립트 문법(Non Required)
#3. 자바스크립트 데이타 타입(Non Required)
#4. 자바스크립트 변수 (Non Required)
변수의 타입
자바스크립트의 변수는 여타 다른 언어들과는 다르게 특정한 타입이 지정되지 않습니다. 따라서, <#3. 자바스크립트 데이타 타입>에서 다루었듯이 대부분의 데이타는 다른 데이타 타입으로 자동 변환됩니다. 이 특성은 자바스크립트를 더 단순한 언어로 만들어줍니다.(라고 책에 소개되지만, 오히려 자동 변환되는 특성을 가지는 언어일수록 신중하게 접근하여야 합니다.)
변수의 선언
자바스크립트의 변수 선언은 여타 다른 언어들과 다르지 않습니다. 다만, 자료형을 사용하는 대신 변수를 의미하는 var을 사용합니다.
- var i;
- var sum;
- var i, sum;
- var message = "hello";
- var i = 0, j = 0, k = 0;
- for(var i = 0; i < 10; i++) {
- document.write(i, "<br>");
- }
전역(global) 변수와 지역(local) 변수
전역 변수는 자바스크립트로 작성한 코드를 통틀어 어디서나 접근 가능한 변수입니다. 그러나 지역 변수는 함수 등에서 정의되어 그 밖에서는 접근할 수 없는 변수입니다.(함수의 매개 변수는 대표적인 지역 변수의 하나입니다.)
지역 변수와 전역 변수는 유효 범위가 다른 만큼 같은 이름을 가질 수 있습니다. 전역 변수와 같은 이름을 가지는 지역 변수가 어떤 함수 내에 존재하는 경우, 지역 변수가 전역 변수에 비해 우선 순위를 갖습니다.
- var scope = "global"
- function checkscope() {
- var scope = "local";
- document.write(scope);
- }
- checkscope();
위의 코드의 경우, 첫 줄에 먼저 "global"인 문자열을 가지는 전역 변수 scope이 존재하고, checkscope의 경우 "local"인 문자열을 가지는 지역 변수 scope이 같은 이름으로 존재합니다. 그러나 마지막 줄에서 checkscope()로 function call을 진행하는 경우, 지역 변수가 우선순위를 가지므로, "local"이 출력됩니다.
함수의 중첩
함수는 중첩되어 유효 범위가 다를 수 있습니다. 아래 예제(이 포스트에서 다루는 모든 예제는 'javascript 완벽가이드'에서 따온 것입니다.)에서 함수의 중첩 및 유효 범위를 잘 설명하고 있습니다.
- var scope = "global scope";
- function checkscope() {
- var scope = "local scope";
- function nested() {
- var scope = "nested scope";
- document.write(scope);
- }
- nested();
- }
- checkscope();
여기서 scope는 각각의 유효 범위를 가집니다.
1. 전역적으로 접근 가능한 global 변수인 "global scope"의 scope,
2.checkscope() 안에서 접근 가능한 local 변수인 "local scope" scope,
3.nested() 안에서 접근 가능한 가장 좁은 유효 범위를 가지는 local 변수인 "nested scope"의 scope.
따라서 8번째 줄의 nested()의 function call이 이루어 졌을 때, 6번 째 줄의 document.write(scope)에 의해 document.write("nested scope")가 출력될 것이며, 10번 째 줄의 checkscope()의 function call이 이루어 졌을 때 역시 같은 결과가 나올 것이라는 것을 알 수 있습니다.
1. 전역적으로 접근 가능한 global 변수인 "global scope"의 scope,
2.checkscope() 안에서 접근 가능한 local 변수인 "local scope" scope,
3.nested() 안에서 접근 가능한 가장 좁은 유효 범위를 가지는 local 변수인 "nested scope"의 scope.
따라서 8번째 줄의 nested()의 function call이 이루어 졌을 때, 6번 째 줄의 document.write(scope)에 의해 document.write("nested scope")가 출력될 것이며, 10번 째 줄의 checkscope()의 function call이 이루어 졌을 때 역시 같은 결과가 나올 것이라는 것을 알 수 있습니다.
색다른 유효 범위를 가지는 자바스크립트
C, C++, Java와는 다르게 자바스크립트는 한 번 함수안에 정의된 변수는 블록에 상관없이 함수 전체에서 유효합니다. (이를 책에서는 '블록 단위의 유효 범위는 없다'라고 설명합니다.)
- function test (o) {
- var i = 0;
- if (typeof o == "object") {
- var j = 0;
- for (var k = 0; k <10; k++) {
- document.write(k);
- }
- document.write(k);
- }
- document.write(j);
- }
위의 test function을 보게 되면, 지역 변수인 i가 test내에서 가장 먼저 선언되고 초기화 되었습니다. 그리고 그 뒤를 이어 조건문이 나오고 조건문 안에서 지역 변수인 j 와 k가 선언되었습니다. 특이한 점은 8번 째 줄의 document.write(k)에서 이루어 집니다.
우리가 그동안 익숙하게 사용해 왔던 언어에서는 8번 째 줄이 허용되지 않았겠지만, javascript 에서는 함수 내에 한 번 정의된 변수가 유지되기 때문에 k가 10으로 정의되고 초기화 되어 출력됩니다.
그러나 10번 째 줄의 경우는 j가 정의되어 있지만, 초기화 되지 않았을 경우에만 출력하기 때문에 undefined가 나타나게 됩니다.
하나의 재밌는 예시를 더 보겠습니다.
지금까지의 프로그래밍 지식으로는 당연히 출력값으로 각각 "global"과 "local"이 나올 것이라고 생각됩니다. 그러나 이 결과는 놀랍게도 undefined와 "local"이 출력됩니다. 그 이유는 Javascript가 인터프리터 언어이고, 자바스크립트의 특성상 함수 전체에서 지역 변수가 전역 변수를 감추는 역할을 하기 때문에, 위의 함수 f()는 다음과 같이 해석됩니다.
따라서, 함수의 시작 부분에 변수를 위치시키는 습관을 들이는 것이 좋습니다. (엄격한 문법 규칙을 가지고 있는 C나 C++과 같은 언어로 프로그래밍 언어 습관을 들여 놓는 것이 자동으로 배정해 주는 javascript와 같은 언어로 프로그래밍을 할 때 오류를 줄이는 것을 도와줍니다.)
우리가 그동안 익숙하게 사용해 왔던 언어에서는 8번 째 줄이 허용되지 않았겠지만, javascript 에서는 함수 내에 한 번 정의된 변수가 유지되기 때문에 k가 10으로 정의되고 초기화 되어 출력됩니다.
그러나 10번 째 줄의 경우는 j가 정의되어 있지만, 초기화 되지 않았을 경우에만 출력하기 때문에 undefined가 나타나게 됩니다.
하나의 재밌는 예시를 더 보겠습니다.
- var scope = "global"
- function f() {
- alert(scope);
- var scope = "local";
- alert(scope);
- }
- f();
- function f() {
- var scope;
- alert(scope);
- var scope = "local";
- alert(scope);
- }
기본 타입과 참조 타입, 그리고 문자열
#4를 시작할 때 자바스크립트의 변수는 타입을 가지지 않는다고 언급 하였습니다. 그러나 자바스크립트의 변수는 자료형을 가지지는 않지만 변수를 크게 기본 타입과 참조 타입으로 나눌 수 있습니다. <#3. 자바스크립트 데이타 타입> 에서 볼 수 있듯이, 숫자, Boolean, null, undefined 데이타 타입은 기본 타입, Object계열의 객체, 함수, Array 데이타 타입은 참조 타입에 속합니다.
기본 타입과 참조 타입의 가장 큰 차이점은 메모리에서 결정된다. 기본 타입은 고정된 크기의 메모리를 할당받아 이용하지만, 참조 타입은 할당받는 메모리의 크기가 고정되어 있지 않습니다. 즉, 변수에 (예컨데 8 비트의) 기본 타입은 얼마든지 저장이 가능하지만 참조 타입은 불가능 하기 때문에 대신 메모리 주소를 저장하여 그 위치를 '참조'합니다.
기본 타입과 참조 타입의 변수는 각각 다르게 동작합니다.
- var a = 3.14;
- var b = a;
- a = 4;
- alert(b);
- var a = [1, 2, 3];
- var b = a;
- a[0] = 99;
- alert(b);
문자열의 경우는 기본 타입과 참조 타입 둘 중 어느 곳에도 속하지 않는 예외적인 경우입니다. 문자열의 크기는 문자가 어떻게 조합되는가에 따라 유동적이기 때문에 고정된 크기의 메모리를 할당 할 수 없습니다. 이 면만 생각해 보면 문자열은 참조 타입의 변수로 지정해도 큰 문제가 없습니다. 그러나 많은 경우에 문자열은 기본 타입의 변수처럼 작동하기 때문에 예외적인 경우로 분리해 둡시다.
가비지 컬렉션
변수는 메모리를 잡아먹습니다. 기본 변수는 크게 문제 되지 않지만, 크기가 유동적인 참조 변수의 경우는 동적으로 메모리에 할당되어 해제되지 않는 경우 메모리에 영구적으로 붙게되어 메모리를 잡아먹게 됩니다. 이를 방지하여 메모리의 손실을 막기 위해서는 '가비지 컬렉션'을 통해 변수의 메모리 할당을 해제하는 작업이 필요합니다.
C와 C++의 경우는 수동으로 변수의 메모리 할당을 해제해야 하기 때문에 프로그래머가 일일이 프로그램에 의해 생성되는 객체의 메모리를 찾아 해제하는 작업을 해주어야 합니다.(물론, 소스 코드 내에서 진행하지만, 불편한 작업이라는 것은 분명합니다.)
자바스크립트에서는 이러한 귀찮은 작업을 줄이기 위하여(자바스크립트는 접근성을 용이하게 하기 위해 많은 이와 같은 귀찮은 작업들을 자동화 시킵니다.) 가비지 컬렉션을 이용합니다. 파이썬에서도 가비지 컬렉터를 이용하여 이러한 문제를 해결합니다.
가비지 컬렉션을 사용하는 것의 장단점은 다음과 같습니다. 일단 가비지 컬렉션을 사용하면 개발 속도가 빨라지고, 발생할 수 있는 오류의 가능성이 줄어듭니다. 그러나 수동으로 메모리를 따라가는 것이 프로그램의 효율성을 증대시켜 속도와 효율을 증가시킵니다. (ios는 C기반, Android는 java기반이라고 알고 있습니다. 이 둘의 차이는 이러한 면에서도 부각되는 면이 있을 것이라 생각합니다)
댓글 없음:
댓글 쓰기