string, number,bigint, boolean, undefined, symbol, (null)
을 말한다. 원시 자료형은 모두 "하나"의 정보, 즉, 데이터를 담고 있다.
원시 자료형은 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수는 있다.
자바스크립트에서 원시 자료형이 아닌 모든 것은 참조 자료형이다. 배열([])과 객체({}), 함수(function(){})가 대표적인데, 이런 자료형을 자바스크립트에서는 참조 자료형(reference data type; 참조 타입)이라고도 부른다.
참조 자료형에는 하나의 데이터가 아닌 여러 데이터가 담기게 되기 때문에, 참조 자료형의 데이터 자체는 지금까지 배웠던 원시 자료형이 보관되는 데이터 보관함이 아닌 특별한 데이터 보관함에 저장된다. 이 데이터가 위치한 곳(메모리 상 주소)을 가리키는 주소가 변수에 저장된다. 즉, 변수에는 특별한 데이터 보관함을 찾아갈 수 있는 주소가 담겨있고, 이 주소를 따라가보면 특별한 데이터 보관함을 찾을 수 있는데, 이 특별한 데이터 보관함에서는 자기 마음데로 사이즈를 늘렸다가 줄였다가 한다. ("동적(dynamic)으로 변한다"라고 하기도 한다.) 이처럼 데이터는 별도로 관리되고, 우리가 직접 다루는 변수에는 주소가 저장되기 때문에 reference type이라고 불린다. 이런 특별한 데이터 보관함을 heap이라고도 부른다.
배열과 객체는 대량의 데이터를 쉽게 다루기 위해서 사용 되는데, 쉽게 사용할 수 있는 이유는 크기가 고정되어 있지 않고 우리가 데이터를 추가하고 삭제하는 것에 따라서 크기가 달라지기 때문이다. 대량의 데이터가 들어오는 경우는 고정된 데이터 공간을 사용하는 것이 비효율적입니다. 그렇기 때문에, 크기가 상황에 따라서 커졌다가 작아지는 특별한 데이터 저장소를 만들어 사용하기로 합의했는데, 데이터가 언제 늘어나고 줄어들지 모르기 때문에 별도의 저장공간을 마련하여 따로 관리하는 것이다. 변수에는 원시값 혹은 주소만 지정할 수 있고, 주소는 크기가 변하는 특별한 데이터 저장소를 참조하게 되는 것이다.
원시 자료형과 참조 자료형의 특징
- 원시 자료형이 할당될 때에는 변수에 값(Value)가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다.
- 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용할 수 있다.
let 키워드는 재선언을 방지하기 때문에, var 키워드보다 let 키워드가 안전하다. 실제로 코딩할 때에 변수를 재선언해야 할 필요가 없고 대부분 이런 경우는 버그이기 때문이다.
전역 변수에 너무 많은 변수를 선언하지 말것!
전역 변수는 어디서든 접근 가능한 변수이기 때문에, 편리한 대신 다른 함수 혹은 로직에 의해 의도되지 않은 변경이 발생할수 있기때문이다.
보통 애플리케이션을 만들 때에는, 내가 직접 작성하지 않은 수많은 다른 함수와 로직이 포함된다. 너도나도 똑같은 이름으로 전역 변수를 선언하려고 한다면 분명 문제가 발생할 것인데, 이를 side effect라고 한다. 전역 변수를 최소화하는 것은 side effect를 줄이는 좋은 방법이다.
Strict Mode는 브라우저가 보다 엄격하게 작동하도록 만들어준다. 앞서 언급한 것처럼 "선언 없는 변수 할당"의 경우도 Strict Mode는 에러로 판단한다. Strict Mode를 적용하려면, js 파일 상단에 'use strict' 라고 입력하면 된다. (따옴표 포함)
클로저 함수의 첫번째 특징은 "함수를 리턴하는 함수"이다. 함수를 리턴하는 함수가 클로저의 형태를 만든다.
클로저는 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분된다. 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(closure; 폐쇄) 데에 있다. 따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요하다.
클로저 함수의 두번째 특징은 "내부 함수는 외부 함수에 선언된 변수에 접근 가능하다"는 점이다.
일반적인 함수는, 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없다. 이와 다르게, 클로저는 외부 함수의 실행이 끝나더라도, 외부 함수 내 변수가 메모리 상에 저장된다. (어휘적 환경을 메모리에 저장하기 때문에 가능한 일이다.)
예제) 예제에서
divMaker
함수는 'div'라는 문자열을 tag
라는 변수에 담아두고 있으며, anchorMaker
함수는 'a'라는 문자열을 tag
에 담아두고 있다. 클로저는 이처럼 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게 해준다.
클로저를 이용해 내부 함수를 단 하나만 리턴하는 것에 그치지 않고, 객체에 담아 여러 개의 내부 함수를 리턴하도록 만들수 있다. 따라서 counter1은 객체이다.
여기서, (makeCounter 함수를 바꾸지 않고) value라는 변수에 값을 새롭게 할당 할 수 없는데, '외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다'는 규칙에 의해, 어떤 경우에도 value
는 직접 수정이 불가능하다. 대신, 리턴하는 객체가 제공하는 메소드를 통해 value
값을 간접적으로 조작할 수 있다. 이것이 정보의 접근 제한 (캡슐화)이다.
만일 스코프로 value 값을 감싸지 않았더라면, value 값은 전역 변수여야만 했을 것이다. 하지만 makeCounter라는 함수가 value 값을 보존하고 있기 때문에, 전역 변수로 따로 만들 필요가 없다.
전역 변수가 좋지 않은 이유는, 전역 변수는 다른 함수 혹은 로직 등에 의해 의도되지 않은 변경을 초래하기 때문이다. 이를 side effect라고 합니다. side effect를 최소화하면, 의도되지 않은 변경을 줄일 수 있습니다. 따라서 이에 따른 오류로부터 보다 안전하게 값을 보호할 수 있다.
클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다.