JavaScript란?
웹페이지의 보조적인 기능을 수행하기위해 만든 경량 프로그래밍 언어이다. 그러나 초기의 단순한 보조적인 역활을 하던 언어에서 Ajax, jQuery, node.js 와 같은 등장으로 단순히 보조하는 역활을 넘어서 어엿한 하나의 프로그래밍 언어로써 사랑을 받고 있다.
그중 나는 Node.js와 npm을 이용하여 공부하려한다.
Node.js(이하 노드)에 대해 간략히 설명하자면 2009년 라이언달에 의해 발표된 자바스크립트 런타임 환경이다.
npm은 자바 스크립트 매니저인데 노드에서 사용할 수 있는 모듈들을 패키지화하여 모아둔 저장소 역활과, 패키지 설치 관리를 위한 CLI(Command line interface)를 제공한다.
노드는 http://nodejs.org 공식 사이트에서 다운받을 수 있다. 이후 명령프롬포트(cmd) 혹은 터미널에서 노드의 버전을 확인하여 정상설치 되었는지 확인할 수 있다.
변수는 하나의 값을 저장하기 위한 메모리 공간이라고 정의할 수 있다. 기본적으로 하나의 변수에는 하나의 값을 지정할 수 있다. 여러개의 값을 지정하기 위해서는 변수 또한 여러개 선언해주거나 배열이나 객체와 같은 자료구조의 형식으로 저장해야한다.
var 은 variable의 약자로써 JS에서 변수를 선언 할 때 사용한다. (ES6부터는 let, const가 추가되었다. 이는 후술할 예정이다.)
이러한 변수의 이름을 식별자(identifier) 라고 하는데 위의 사진에서 one, two, user를 식별자라고 부른다. 식별자는 변수의 값을 기억하고있는데 더 정확히는 변수의 값이 저장된 메모리 주소를 기억하는것이다. 컴퓨터는 메모리에 값을 기억하고 CPU를 이용하여 연산을 하는데, 메모리는 값을 저장할 수 있는 메모리 셀들의 집합이다. 메모리 셀은 1Byte(=8bit)의 저장공간을 할당하는데, 1Byte단위로 값을 저장하거나 읽어온다. 즉 식별자는 이 메모리셀의 위치인 메모리 주소를 식별함으로써 메모리값을 읽어오는것이다. 예를 들어 변수 twosome에 place라는 값을 적었다면 place라는 데이터값이 메모리안의 어느 특정 메모리셀에 할당되고 그 주소가 0x00234032이라 할때 twosome은 place를 식별하는것이아닌 주소 0x00234032 를 식별하여 그 안의 값 place를 불러오는것이다.
그럼 이제 좀 더 심화적인 이야기로 들어가보자.
var를 통하여 변수를 선언할때 변수는 어떤 type으로도 선언이 가능한데, 예를들어 다른언어에서는 int, float, string, double 등등 다양한 해당 type에 맞는 변수를 선언해줘야하는데 var는 그럴필요가 없다. 위 사진을 보면 해당 type에 맞게 변수를 선언해 준게 아닌 var을 통하여 선언해주는 모습을 볼 수 있다.
그럼 이렇게 좋은 var를 두고 왜 개발자들은 ES6에서 let과 const를 선언했을까? 그 이유를 알기 위해서는 var의 치명적 단점에 대해 알아야한다.
var는 선언할 때 블록 레벨 스코프가 아닌 함수레벨 스코프로 선언된다는 치명적인 단점이 있다. 이는 의도치않게 전역 변수가 선언되어 심각한 부작용을 낳을 가능성이 있다. 그러나 스코프의 개념을 모르면 이것이 왜? 어째서? 단점이 될지 모를 가능성이 크다. 그렇기에 스코프 개념부터 짚고 넘어가려한다.
스코프란 식별자를 찾아내기 위한 일종의 규칙이다. 식별자는 자신이 어디에서 선언이 되었는지에 따라 자신이 유효한(다른 코드가 자신을 참조할 수 있는) 범위를 갖는다. 그렇기에 전 영역에서 사용할 수 있는 전역 스코프와, 해당지역에서 사용할 수 있는 지역 스코프로 나뉘는데 이를 변수의 관점에서 볼때 우리가 흔히 말하는 전역변수와 지역변수가 된다.
대부분 언어들은 블록 레벨 스코프(block-level-scope)를 따르는데, 블록 레벨 스코프는 블록( {}나 () 같은) 안에서만 함수가 유효한(참조할 수 있는) 스코프이다. 그러나 자바 스크립트의 경우 블록 레벨 스코프가 아닌 함수 레벨 스코프(Function-level-scope)이다. 함수 레벨 스코프는 함수안에서만 유효한 스코프인데, 문제는 자바스크립트의 단점 중 하나인 중복 허용으로 인해 함수 밖의 변수 A가 있다고 가정할때 {} 안에서 새로 A라는 변수를 선언해도 중복 허용 하여 {}밖의 전역변수 A는 {} 안의 지역변수 A로 인하여 값이 변경되어 오류가 발생할 가능성이 다분해진다.
[예시 사진 - one의 값이 바뀌어버린 모습을 볼 수 있다.]
또한 변수(변수 뿐만이 아니라 JS내에서의 모든 선언들)는 Hoisting 이라는 것을 하는데 Hoisting이란 해당 변수나 선언에 앞서 메모리공간을 미리 받는 것을 뜻한다. 이는 JS내에서 미리 호출을 선언보다 앞에 할수 있게해준다.[예시 사진 - 함수를 먼저 호출하고 변수를 선언하여도 아무 문제가 없음을 보여준다.]
그래서 이런 기능이 있는건 알겠는데 이게 뭐 어쨌다는거야? 라고 생각할 수 있는데 이는 변수의 생성 과정에서 문제가 직관된다.
변수는 3단계에 걸쳐 생성되는데
선언
선언단계의 경우 변수명을 JS에게 알려 해당 변수명을 통해 변수를 사용할것이라는것을 알리는 단계이다.
초기화
선언된 변수를 위해 메모리에 공간을 확보하고 변수를 암묵적으로 undefined로 초기화 시킨다.
할당
undefined로 초기화 된 변수에 값을 할당한다.
( ! 만약 2단계 초기화를 거치지 않게 되면 확보된 메모리 공간에 다른 에플리케이션에서 사용했던 값이 남아있을 수 있는데 이를 garbage value (쓰레기 값) 이라고한다. 이는 garbage collector 라고 하는 기능이 담당하는데 할당공간을 주기적으로 검사하여 더이상 사용하지 않는 메모리를 release(해제) 시킨다.)
해당과정에서 var는 1번과 2번을 hoisting하고 let과 const는 1번만 hoisting한다(※호이스팅은 따로 작성할예정이다.)
위와 같은 이유로 var는 그냥 사용하기에는 주의해야할점이 너무 많기에 좀 더 편하게 언어를 사용하고자 let과 const를 추가하였다. let 과 const는 함수 레벨 스코프가 아닌 블록 레벨 스코프이다. 위의 예시인 A로 다시한번 예시를 들어보면, 전역변수 A를 let으로 선언하고, {}안에서 let을 지역변수let A,B를 선언 할 경우 {}안에서의 let A,B는 존재하나 밖으로 나올경우 지역변수 A,B는 존재하지 않고 전역변수 A만이 남게된다.
[예시 사진 - 위의 사진 one과는 다르게 a의 값이 변하지 않은것을 볼 수 있다.]
let 과 const는 둘다 블록 레벨 스코프인데 둘의 가장 큰 차이는 재할당 허용의 차이이다.
let은 재할당을 허용하는 반면 const는 재할당을 허용하지 않는다.
[예시 사진 - let은 재할당을 허용하여 a의 값을 1로 바꾸어 주었으나 const는 허용하지않기에 TypeError가 실행되었다.]
const는 다른언어의 상수와도 같아 보일 수 있지만(실제로 단어자체의 뜻 또한 같지만) JS에서의 const는 꼭 상수로써만 사용되지않는다. 이는 나중에 다시 다뤄볼것이다.